CTF-All-In-One/doc/6.1.16_pwn_hitbctf2017_1000levels.md
2018-04-21 12:02:03 +08:00

334 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 6.1.16 pwn HITBCTF2017 1000levels
- [题目复现](#题目复现)
- [题目解析](#题目解析)
- [Exploit](#exploit)
- [参考资料](#参考资料)
[下载文件](../src/writeup/6.1.16_pwn_hitbctf2017_1000levels)
## 题目复现
```
$ file 1000levels
1000levels: 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.32, BuildID[sha1]=d0381dfa29216ed7d765936155bbaa3f9501283a, not stripped
$ checksec -f 1000levels
RELRO STACK CANARY NX PIE RPATH RUNPATH FORTIFY Fortified Fortifiable FILE
Partial RELRO No canary found NX enabled PIE enabled No RPATH No RUNPATH No 0 6 1000levels
$ strings libc.so.6 | grep "GNU C"
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu9) stable release version 2.23, by Roland McGrath et al.
Compiled by GNU CC version 5.4.0 20160609.
```
关闭了 Canary开启 NX 和 PIE。于是猜测可能是栈溢出但需要绕过 ASLR。not stripped 可以说是很开心了。
玩一下:
```
$ ./1000levels
Welcome to 1000levels, it's much more diffcult than before.
1. Go
2. Hint
3. Give up
Choice:
1
How many levels?
0
Coward
Any more?
1
Let's go!'
====================================================
Level 1
Question: 0 * 0 = ? Answer:0
Great job! You finished 1 levels in 1 seconds
```
Go 的功能看起来就是让你先输入一个数,然后再输入一个数,两个数相加作为 levels然后让你做算术。
但是很奇怪的是,如果你使用了 Hint 功能,然后第一个数输入了 0 的时候,无论第二个数是多少,仿佛都会出现无限多的 levels
```
$ ./1000levels
Welcome to 1000levels, it's much more diffcult than before.
1. Go
2. Hint
3. Give up
Choice:
2
NO PWN NO FUN
1. Go
2. Hint
3. Give up
Choice:
1
How many levels?
0
Coward
Any more?
1
More levels than before!
Let's go!'
====================================================
Level 1
Question: 0 * 0 = ? Answer:0
====================================================
Level 2
Question: 1 * 1 = ? Answer:1
====================================================
Level 3
Question: 1 * 1 = ? Answer:1
====================================================
Level 4
Question: 3 * 1 = ? Answer:
```
所以应该重点关注一下 Hint 功能。
## 题目解析
程序比较简单,基本上只有 Go 和 Hint 两个功能。
#### go
```
[0x000009d0]> pdf @ sym.go
/ (fcn) sym.go 372
| sym.go ();
| ; var int local_120h @ rbp-0x120
| ; var int local_118h @ rbp-0x118
| ; var int local_114h @ rbp-0x114
| ; var int local_110h @ rbp-0x110
| ; var int local_108h @ rbp-0x108
| ; CALL XREF from 0x00000f9f (main)
| 0x00000b7c push rbp
| 0x00000b7d mov rbp, rsp
| 0x00000b80 sub rsp, 0x120
| 0x00000b87 lea rdi, str.How_many_levels ; 0x1094 ; "How many levels?"
| 0x00000b8e call sym.imp.puts ; int puts(const char *s)
| 0x00000b93 call sym.read_num ; ssize_t read(int fildes, void *buf, size_t nbyte)
| 0x00000b98 mov qword [local_120h], rax ; 将第一个数放进 local_120h
| 0x00000b9f mov rax, qword [local_120h]
| 0x00000ba6 test rax, rax
| ,=< 0x00000ba9 jg 0xbb9
| | 0x00000bab lea rdi, str.Coward ; 0x10a5 ; "Coward"
| | 0x00000bb2 call sym.imp.puts ; int puts(const char *s)
| ,==< 0x00000bb7 jmp 0xbc7
| || ; JMP XREF from 0x00000ba9 (sym.go)
| |`-> 0x00000bb9 mov rax, qword [local_120h]
| | 0x00000bc0 mov qword [local_110h], rax
| | ; JMP XREF from 0x00000bb7 (sym.go)
| `--> 0x00000bc7 lea rdi, str.Any_more ; 0x10ac ; "Any more?"
| 0x00000bce call sym.imp.puts ; int puts(const char *s)
| 0x00000bd3 call sym.read_num ; ssize_t read(int fildes, void *buf, size_t nbyte)
| 0x00000bd8 mov qword [local_120h], rax
| 0x00000bdf mov rdx, qword [local_110h]
| 0x00000be6 mov rax, qword [local_120h]
| 0x00000bed add rax, rdx ; '('
| 0x00000bf0 mov qword [local_110h], rax
| 0x00000bf7 mov rax, qword [local_110h]
| 0x00000bfe test rax, rax
| ,=< 0x00000c01 jg 0xc14
| | 0x00000c03 lea rdi, str.Coward ; 0x10a5 ; "Coward"
| | 0x00000c0a call sym.imp.puts ; int puts(const char *s)
| ,==< 0x00000c0f jmp 0xcee
| |`-> 0x00000c14 mov rax, qword [local_110h]
| | 0x00000c1b cmp rax, 0x3e7
| |,=< 0x00000c21 jle 0xc3c
| || 0x00000c23 lea rdi, str.More_levels_than_before ; 0x10b6 ; "More levels than before!"
| || 0x00000c2a call sym.imp.puts ; int puts(const char *s)
| || 0x00000c2f mov qword [local_108h], 0x3e8
| ,===< 0x00000c3a jmp 0xc4a
| ||| ; JMP XREF from 0x00000c21 (sym.go)
| ||`-> 0x00000c3c mov rax, qword [local_110h]
| || 0x00000c43 mov qword [local_108h], rax
| || ; JMP XREF from 0x00000c3a (sym.go)
| `---> 0x00000c4a lea rdi, str.Let_s_go ; 0x10cf ; "Let's go!'"
| | 0x00000c51 call sym.imp.puts ; int puts(const char *s)
| | 0x00000c56 mov edi, 0
| | 0x00000c5b call sym.imp.time ; time_t time(time_t *timer)
| | 0x00000c60 mov dword [local_118h], eax
| | 0x00000c66 mov rax, qword [local_108h]
| | 0x00000c6d mov edi, eax
| | 0x00000c6f call sym.level_int ; 进入计算题游戏
| | 0x00000c74 test eax, eax
| | 0x00000c76 setne al
| | 0x00000c79 test al, al
| |,=< 0x00000c7b je 0xcd8
| || 0x00000c7d mov edi, 0
| || 0x00000c82 call sym.imp.time ; time_t time(time_t *timer)
| || 0x00000c87 mov dword [local_114h], eax
| || 0x00000c8d mov edx, dword [local_114h]
| || 0x00000c93 mov eax, dword [local_118h]
| || 0x00000c99 sub edx, eax
| || 0x00000c9b mov rax, qword [local_108h]
| || 0x00000ca2 lea rcx, [local_120h]
| || 0x00000ca9 lea rdi, [rcx + 0x20] ; "@"
| || 0x00000cad mov ecx, edx
| || 0x00000caf mov rdx, rax
| || 0x00000cb2 lea rsi, str.Great_job__You_finished__d_levels_in__d_seconds ; 0x10e0 ; "Great job! You finished %d levels in %d seconds\n"
| || 0x00000cb9 mov eax, 0
| || 0x00000cbe call sym.imp.sprintf ; int sprintf(char *s,
| || 0x00000cc3 lea rax, [local_120h]
| || 0x00000cca add rax, 0x20
| || 0x00000cce mov rdi, rax
| || 0x00000cd1 call sym.imp.puts ; int puts(const char *s)
| ,===< 0x00000cd6 jmp 0xce4
| ||| ; JMP XREF from 0x00000c7b (sym.go)
| ||`-> 0x00000cd8 lea rdi, str.You_failed. ; 0x1111 ; "You failed."
| || 0x00000cdf call sym.imp.puts ; int puts(const char *s)
| || ; JMP XREF from 0x00000cd6 (sym.go)
| `---> 0x00000ce4 mov edi, 0
| | 0x00000ce9 call sym.imp.exit ; void exit(int status)
| | ; JMP XREF from 0x00000c0f (sym.go)
| `--> 0x00000cee leave
\ 0x00000cef ret
```
计算题游戏的函数 `sym.level_int()` 如下:
```
[0x000009d0]> pdf @ sym.level_int
/ (fcn) sym.level_int 289
| sym.level_int ();
| ; var int local_34h @ rbp-0x34
| ; var int local_30h @ rbp-0x30
| ; var int local_28h @ rbp-0x28
| ; var int local_20h @ rbp-0x20
| ; var int local_18h @ rbp-0x18
| ; var int local_10h @ rbp-0x10
| ; var int local_ch @ rbp-0xc
| ; var int local_8h @ rbp-0x8
| ; var int local_4h @ rbp-0x4
| ; CALL XREF from 0x00000c6f (sym.go)
| ; CALL XREF from 0x00000e70 (sym.level_int)
| 0x00000e2d push rbp
| 0x00000e2e mov rbp, rsp
| 0x00000e31 sub rsp, 0x40 ; '@'
| 0x00000e35 mov dword [local_34h], edi
| 0x00000e38 mov qword [local_30h], 0
| 0x00000e40 mov qword [local_28h], 0
| 0x00000e48 mov qword [local_20h], 0
| 0x00000e50 mov qword [local_18h], 0
| 0x00000e58 cmp dword [local_34h], 0
| ,=< 0x00000e5c jne 0xe68
| | 0x00000e5e mov eax, 1
| ,==< 0x00000e63 jmp 0xf4c
| || ; JMP XREF from 0x00000e5c (sym.level_int)
| |`-> 0x00000e68 mov eax, dword [local_34h]
| | 0x00000e6b sub eax, 1
| | 0x00000e6e mov edi, eax
| | 0x00000e70 call sym.level_int
| | 0x00000e75 test eax, eax
| | 0x00000e77 sete al
| | 0x00000e7a test al, al
| |,=< 0x00000e7c je 0xe88
| || 0x00000e7e mov eax, 0
| ,===< 0x00000e83 jmp 0xf4c
| ||| ; JMP XREF from 0x00000e7c (sym.level_int)
| ||`-> 0x00000e88 call sym.imp.rand ; int rand(void)
| || 0x00000e8d cdq
| || 0x00000e8e idiv dword [local_34h]
| || 0x00000e91 mov dword [local_8h], edx
| || 0x00000e94 call sym.imp.rand ; int rand(void)
| || 0x00000e99 cdq
| || 0x00000e9a idiv dword [local_34h]
| || 0x00000e9d mov dword [local_ch], edx
| || 0x00000ea0 mov eax, dword [local_8h]
| || 0x00000ea3 imul eax, dword [local_ch]
| || 0x00000ea7 mov dword [local_10h], eax
| || 0x00000eaa lea rdi, str. ; 0x1160 ; "===================================================="
| || 0x00000eb1 call sym.imp.puts ; int puts(const char *s)
| || 0x00000eb6 mov eax, dword [local_34h]
| || 0x00000eb9 mov esi, eax
| || 0x00000ebb lea rdi, str.Level__d ; 0x1195 ; "Level %d\n"
| || 0x00000ec2 mov eax, 0
| || 0x00000ec7 call sym.imp.printf ; int printf(const char *format)
| || 0x00000ecc mov edx, dword [local_ch]
| || 0x00000ecf mov eax, dword [local_8h]
| || 0x00000ed2 mov esi, eax
| || 0x00000ed4 lea rdi, str.Question:__d____d_____Answer: ; 0x119f ; "Question: %d * %d = ? Answer:"
| || 0x00000edb mov eax, 0
| || 0x00000ee0 call sym.imp.printf ; int printf(const char *format)
| || 0x00000ee5 lea rax, [local_30h]
| || 0x00000ee9 mov edx, 0x400
| || 0x00000eee mov rsi, rax
| || 0x00000ef1 mov edi, 0
| || 0x00000ef6 call sym.imp.read ; ssize_t read(int fildes, void *buf, size_t nbyte)
| || 0x00000efb mov dword [local_4h], eax
| || ; JMP XREF from 0x00000f16 (sym.level_int)
| ||.-> 0x00000efe mov eax, dword [local_4h]
| ||: 0x00000f01 and eax, 7
| ||: 0x00000f04 test eax, eax
| ,====< 0x00000f06 je 0xf18
| |||: 0x00000f08 mov eax, dword [local_4h]
| |||: 0x00000f0b cdqe
| |||: 0x00000f0d mov byte [rbp + rax - 0x30], 0
| |||: 0x00000f12 add dword [local_4h], 1
| |||`=< 0x00000f16 jmp 0xefe
| ||| ; JMP XREF from 0x00000f06 (sym.level_int)
| `----> 0x00000f18 lea rax, [local_30h]
| || 0x00000f1c mov edx, 0xa
| || 0x00000f21 mov esi, 0
| || 0x00000f26 mov rdi, rax
| || 0x00000f29 call sym.imp.strtol ; long strtol(const char *str, char**endptr, int base)
| || 0x00000f2e mov rdx, rax
| || 0x00000f31 mov eax, dword [local_10h]
| || 0x00000f34 cdqe
| || 0x00000f36 cmp rdx, rax
| || 0x00000f39 sete al
| || 0x00000f3c test al, al
| ||,=< 0x00000f3e je 0xf47
| ||| 0x00000f40 mov eax, 1
| ,====< 0x00000f45 jmp 0xf4c
| |||| ; JMP XREF from 0x00000f3e (sym.level_int)
| |||`-> 0x00000f47 mov eax, 0
| ||| ; JMP XREF from 0x00000f45 (sym.level_int)
| ||| ; JMP XREF from 0x00000e83 (sym.level_int)
| ||| ; JMP XREF from 0x00000e63 (sym.level_int)
| ```--> 0x00000f4c leave
\ 0x00000f4d ret
```
#### hint
```
[0x000009d0]> pdf @ sym.hint
/ (fcn) sym.hint 140
| sym.hint ();
| ; var int local_110h @ rbp-0x110
| ; CALL XREF from 0x00000fa6 (main)
| 0x00000cf0 push rbp
| 0x00000cf1 mov rbp, rsp
| 0x00000cf4 sub rsp, 0x110
| 0x00000cfb mov rax, qword [reloc.system] ; [0x201fd0:8]=0
| 0x00000d02 mov qword [local_110h], rax
| 0x00000d09 lea rax, obj.show_hint ; 0x20208c
| 0x00000d10 mov eax, dword [rax]
| 0x00000d12 test eax, eax
| ,=< 0x00000d14 je 0xd41
| | 0x00000d16 mov rax, qword [local_110h]
| | 0x00000d1d lea rdx, [local_110h]
| | 0x00000d24 lea rcx, [rdx + 8]
| | 0x00000d28 mov rdx, rax
| | 0x00000d2b lea rsi, str.Hint:__p ; 0x111d ; "Hint: %p\n"
| | 0x00000d32 mov rdi, rcx
| | 0x00000d35 mov eax, 0
| | 0x00000d3a call sym.imp.sprintf ; int sprintf(char *s,
| ,==< 0x00000d3f jmp 0xd66
| || ; JMP XREF from 0x00000d14 (sym.hint)
| |`-> 0x00000d41 lea rax, [local_110h]
| | 0x00000d48 add rax, 8
| | 0x00000d4c movabs rsi, 0x4e204e5750204f4e
| | 0x00000d56 mov qword [rax], rsi
| | 0x00000d59 mov dword [rax + 8], 0x5546204f ; [0x5546204f:4]=-1
| | 0x00000d60 mov word [rax + 0xc], 0x4e ; 'N' ; [0x4e:2]=0
| | ; JMP XREF from 0x00000d3f (sym.hint)
| `--> 0x00000d66 lea rax, [local_110h]
| 0x00000d6d add rax, 8
| 0x00000d71 mov rdi, rax
| 0x00000d74 call sym.imp.puts ; int puts(const char *s)
| 0x00000d79 nop
| 0x00000d7a leave
\ 0x00000d7b ret
```
## Exploit
## 参考资料
- https://ctftime.org/task/4539