CTF-All-In-One/doc/6.1.21_pwn_hitconctf2016_secret_holder.md
2018-05-02 22:27:00 +08:00

20 KiB
Raw Blame History

6.1.21 pwn HITCONCTF2016 Secret_Holder

下载文件

题目复现

$ file SecretHolder 
SecretHolder: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=1d9395599b8df48778b25667e94e367debccf293, stripped
$ checksec -f SecretHolder
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FORTIFY Fortified Fortifiable  FILE
Partial RELRO   Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   Yes     0               2       SecretHolder
$ strings libc.so.6 | grep "GNU C"
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu3) stable release version 2.23, by Roland McGrath et al.
Compiled by GNU CC version 5.3.1 20160413.

64 位程序,开启了 Canary 和 NX默认开启 ASLR。

在 Ubuntu-16.04 上玩一下:

$ ./SecretHolder
Hey! Do you have any secret?
I can help you to hold your secrets, and no one will be able to see it :)
1. Keep secret
2. Wipe secret
3. Renew secret
1
Which level of secret do you want to keep?
1. Small secret
2. Big secret
3. Huge secret
1
Tell me your secret: 
AAAA
1. Keep secret
2. Wipe secret
3. Renew secret
3
Which Secret do you want to renew?
1. Small secret
2. Big secret
3. Huge secret
1
Tell me your secret: 
BBBB
1. Keep secret
2. Wipe secret
3. Renew secret
2
Which Secret do you want to wipe?
1. Small secret
2. Big secret
3. Huge secret
1

该程序运行我们输入 small、big、huge 三种 secret且每种 secret 只能输入一个。通过 Renew 可以修改 secret 的内容。Wipe 用于删除 secret。

猜测三种 secret 应该是有不同的 chunk 大小,但程序没有我们常见的打印信息这种选项来做信息泄漏。

题目解析

下面我们逐个来逆向这些功能。

Keep secret

[0x00400780]> pdf @ sub.Which_level_of_secret_do_you_want_to_keep_86d 
/ (fcn) sub.Which_level_of_secret_do_you_want_to_keep_86d 442
|   sub.Which_level_of_secret_do_you_want_to_keep_86d ();
|           ; var int local_14h @ rbp-0x14
|           ; var int local_10h @ rbp-0x10
|           ; var int local_8h @ rbp-0x8
|           ; CALL XREF from 0x00400d6e (main)
|           0x0040086d      push rbp
|           0x0040086e      mov rbp, rsp
|           0x00400871      sub rsp, 0x20
|           0x00400875      mov rax, qword fs:[0x28]                   ; [0x28:8]=-1 ; '(' ; 40
|           0x0040087e      mov qword [local_8h], rax
|           0x00400882      xor eax, eax
|           0x00400884      mov edi, str.Which_level_of_secret_do_you_want_to_keep ; 0x400e28 ; "Which level of secret do you want to keep?"
|           0x00400889      call sym.imp.puts                          ; int puts(const char *s)
|           0x0040088e      mov edi, str.1._Small_secret               ; 0x400e53 ; "1. Small secret"
|           0x00400893      call sym.imp.puts                          ; int puts(const char *s)
|           0x00400898      mov edi, str.2._Big_secret                 ; 0x400e63 ; "2. Big secret"
|           0x0040089d      call sym.imp.puts                          ; int puts(const char *s)
|           0x004008a2      mov edi, str.3._Huge_secret                ; 0x400e71 ; "3. Huge secret"
|           0x004008a7      call sym.imp.puts                          ; int puts(const char *s)
|           0x004008ac      lea rax, [local_10h]
|           0x004008b0      mov edx, 4
|           0x004008b5      mov esi, 0
|           0x004008ba      mov rdi, rax
|           0x004008bd      call sym.imp.memset                        ; void *memset(void *s, int c, size_t n)
|           0x004008c2      lea rax, [local_10h]
|           0x004008c6      mov edx, 4
|           0x004008cb      mov rsi, rax
|           0x004008ce      mov edi, 0
|           0x004008d3      mov eax, 0
|           0x004008d8      call sym.imp.read                          ; ssize_t read(int fildes, void *buf, size_t nbyte)
|           0x004008dd      lea rax, [local_10h]
|           0x004008e1      mov rdi, rax
|           0x004008e4      call sym.imp.atoi                          ; int atoi(const char *str)
|           0x004008e9      mov dword [local_14h], eax
|           0x004008ec      mov eax, dword [local_14h]
|           0x004008ef      cmp eax, 2                                 ; 2
|       ,=< 0x004008f2      je 0x400963
|       |   0x004008f4      cmp eax, 3                                 ; 3
|      ,==< 0x004008f7      je 0x4009bc
|      ||   0x004008fd      cmp eax, 1                                 ; 1
|     ,===< 0x00400900      je 0x400907
|    ,====< 0x00400902      jmp 0x400a11
|    ||||   ; JMP XREF from 0x00400900 (sub.Which_level_of_secret_do_you_want_to_keep_86d)
|    |`---> 0x00400907      mov eax, dword [0x006020c0]                ; [0x6020c0:4]=0
|    | ||   0x0040090d      test eax, eax
|    |,===< 0x0040090f      je 0x400916
|   ,=====< 0x00400911      jmp 0x400a11
|   |||||   ; JMP XREF from 0x0040090f (sub.Which_level_of_secret_do_you_want_to_keep_86d)
|   ||`---> 0x00400916      mov esi, 0x28                              ; '(' ; 40
|   || ||   0x0040091b      mov edi, 1
|   || ||   0x00400920      call sym.imp.calloc                        ; void *calloc(size_t nmeb, size_t size)
|   || ||   0x00400925      mov qword [0x006020b0], rax                ; [0x6020b0:8]=0
|   || ||   0x0040092c      mov dword [0x006020c0], 1                  ; [0x6020c0:4]=0
|   || ||   0x00400936      mov edi, str.Tell_me_your_secret:          ; 0x400e80 ; "Tell me your secret: "
|   || ||   0x0040093b      call sym.imp.puts                          ; int puts(const char *s)
|   || ||   0x00400940      mov rax, qword [0x006020b0]                ; [0x6020b0:8]=0
|   || ||   0x00400947      mov edx, 0x28                              ; '(' ; 40
|   || ||   0x0040094c      mov rsi, rax
|   || ||   0x0040094f      mov edi, 0
|   || ||   0x00400954      mov eax, 0
|   || ||   0x00400959      call sym.imp.read                          ; ssize_t read(int fildes, void *buf, size_t nbyte)
|   ||,===< 0x0040095e      jmp 0x400a11
|   |||||   ; JMP XREF from 0x004008f2 (sub.Which_level_of_secret_do_you_want_to_keep_86d)
|   ||||`-> 0x00400963      mov eax, dword [0x006020b8]                ; [0x6020b8:4]=0
|   ||||    0x00400969      test eax, eax
|   ||||,=< 0x0040096b      je 0x400972
|  ,======< 0x0040096d      jmp 0x400a11
|  ||||||   ; JMP XREF from 0x0040096b (sub.Which_level_of_secret_do_you_want_to_keep_86d)
|  |||||`-> 0x00400972      mov esi, 0xfa0                             ; 4000
|  |||||    0x00400977      mov edi, 1
|  |||||    0x0040097c      call sym.imp.calloc                        ; void *calloc(size_t nmeb, size_t size)
|  |||||    0x00400981      mov qword [0x006020a0], rax                ; [0x6020a0:8]=0
|  |||||    0x00400988      mov dword [0x006020b8], 1                  ; [0x6020b8:4]=0
|  |||||    0x00400992      mov edi, str.Tell_me_your_secret:          ; 0x400e80 ; "Tell me your secret: "
|  |||||    0x00400997      call sym.imp.puts                          ; int puts(const char *s)
|  |||||    0x0040099c      mov rax, qword [0x006020a0]                ; [0x6020a0:8]=0
|  |||||    0x004009a3      mov edx, 0xfa0                             ; 4000
|  |||||    0x004009a8      mov rsi, rax
|  |||||    0x004009ab      mov edi, 0
|  |||||    0x004009b0      mov eax, 0
|  |||||    0x004009b5      call sym.imp.read                          ; ssize_t read(int fildes, void *buf, size_t nbyte)
|  |||||,=< 0x004009ba      jmp 0x400a11
|  ||||||   ; JMP XREF from 0x004008f7 (sub.Which_level_of_secret_do_you_want_to_keep_86d)
|  ||||`--> 0x004009bc      mov eax, dword [0x006020bc]                ; [0x6020bc:4]=0
|  |||| |   0x004009c2      test eax, eax
|  ||||,==< 0x004009c4      je 0x4009c8
| ,=======< 0x004009c6      jmp 0x400a11
| |||||||   ; JMP XREF from 0x004009c4 (sub.Which_level_of_secret_do_you_want_to_keep_86d)
| |||||`--> 0x004009c8      mov esi, 0x61a80
| ||||| |   0x004009cd      mov edi, 1
| ||||| |   0x004009d2      call sym.imp.calloc                        ; void *calloc(size_t nmeb, size_t size)
| ||||| |   0x004009d7      mov qword [0x006020a8], rax                ; [0x6020a8:8]=0
| ||||| |   0x004009de      mov dword [0x006020bc], 1                  ; [0x6020bc:4]=0
| ||||| |   0x004009e8      mov edi, str.Tell_me_your_secret:          ; 0x400e80 ; "Tell me your secret: "
| ||||| |   0x004009ed      call sym.imp.puts                          ; int puts(const char *s)
| ||||| |   0x004009f2      mov rax, qword [0x006020a8]                ; [0x6020a8:8]=0
| ||||| |   0x004009f9      mov edx, 0x61a80
| ||||| |   0x004009fe      mov rsi, rax
| ||||| |   0x00400a01      mov edi, 0
| ||||| |   0x00400a06      mov eax, 0
| ||||| |   0x00400a0b      call sym.imp.read                          ; ssize_t read(int fildes, void *buf, size_t nbyte)
| ||||| |   0x00400a10      nop
| ||||| |   ; XREFS: JMP 0x00400902  JMP 0x00400911  JMP 0x0040095e  JMP 0x0040096d  JMP 0x004009ba  JMP 0x004009c6  
| `````-`-> 0x00400a11      mov rax, qword [local_8h]
|           0x00400a15      xor rax, qword fs:[0x28]
|       ,=< 0x00400a1e      je 0x400a25
|       |   0x00400a20      call sym.imp.__stack_chk_fail              ; void __stack_chk_fail(void)
|       |   ; JMP XREF from 0x00400a1e (sub.Which_level_of_secret_do_you_want_to_keep_86d)
|       `-> 0x00400a25      leave
\           0x00400a26      ret

Wipe secret

[0x00400780]> pdf @ sub.Which_Secret_do_you_want_to_wipe_a27 
/ (fcn) sub.Which_Secret_do_you_want_to_wipe_a27 247
|   sub.Which_Secret_do_you_want_to_wipe_a27 ();
|           ; var int local_14h @ rbp-0x14
|           ; var int local_10h @ rbp-0x10
|           ; var int local_8h @ rbp-0x8
|           ; CALL XREF from 0x00400d7a (main)
|           0x00400a27      push rbp
|           0x00400a28      mov rbp, rsp
|           0x00400a2b      sub rsp, 0x20
|           0x00400a2f      mov rax, qword fs:[0x28]                   ; [0x28:8]=-1 ; '(' ; 40
|           0x00400a38      mov qword [local_8h], rax
|           0x00400a3c      xor eax, eax
|           0x00400a3e      mov edi, str.Which_Secret_do_you_want_to_wipe ; 0x400e98 ; "Which Secret do you want to wipe?"
|           0x00400a43      call sym.imp.puts                          ; int puts(const char *s)
|           0x00400a48      mov edi, str.1._Small_secret               ; 0x400e53 ; "1. Small secret"
|           0x00400a4d      call sym.imp.puts                          ; int puts(const char *s)
|           0x00400a52      mov edi, str.2._Big_secret                 ; 0x400e63 ; "2. Big secret"
|           0x00400a57      call sym.imp.puts                          ; int puts(const char *s)
|           0x00400a5c      mov edi, str.3._Huge_secret                ; 0x400e71 ; "3. Huge secret"
|           0x00400a61      call sym.imp.puts                          ; int puts(const char *s)
|           0x00400a66      lea rax, [local_10h]
|           0x00400a6a      mov edx, 4
|           0x00400a6f      mov esi, 0
|           0x00400a74      mov rdi, rax
|           0x00400a77      call sym.imp.memset                        ; void *memset(void *s, int c, size_t n)
|           0x00400a7c      lea rax, [local_10h]
|           0x00400a80      mov edx, 4
|           0x00400a85      mov rsi, rax
|           0x00400a88      mov edi, 0
|           0x00400a8d      mov eax, 0
|           0x00400a92      call sym.imp.read                          ; ssize_t read(int fildes, void *buf, size_t nbyte)
|           0x00400a97      lea rax, [local_10h]
|           0x00400a9b      mov rdi, rax
|           0x00400a9e      call sym.imp.atoi                          ; int atoi(const char *str)
|           0x00400aa3      mov dword [local_14h], eax
|           0x00400aa6      mov eax, dword [local_14h]
|           0x00400aa9      cmp eax, 2                                 ; 2
|       ,=< 0x00400aac      je 0x400ad3
|       |   0x00400aae      cmp eax, 3                                 ; 3
|      ,==< 0x00400ab1      je 0x400aee
|      ||   0x00400ab3      cmp eax, 1                                 ; 1
|     ,===< 0x00400ab6      jne 0x400b08
|     |||   0x00400ab8      mov rax, qword [0x006020b0]                ; [0x6020b0:8]=0
|     |||   0x00400abf      mov rdi, rax
|     |||   0x00400ac2      call sym.imp.free                          ; void free(void *ptr)
|     |||   0x00400ac7      mov dword [0x006020c0], 0                  ; [0x6020c0:4]=0
|    ,====< 0x00400ad1      jmp 0x400b08
|    ||||   ; JMP XREF from 0x00400aac (sub.Which_Secret_do_you_want_to_wipe_a27)
|    |||`-> 0x00400ad3      mov rax, qword [0x006020a0]                ; [0x6020a0:8]=0
|    |||    0x00400ada      mov rdi, rax
|    |||    0x00400add      call sym.imp.free                          ; void free(void *ptr)
|    |||    0x00400ae2      mov dword [0x006020b8], 0                  ; [0x6020b8:4]=0
|    |||,=< 0x00400aec      jmp 0x400b08
|    ||||   ; JMP XREF from 0x00400ab1 (sub.Which_Secret_do_you_want_to_wipe_a27)
|    ||`--> 0x00400aee      mov rax, qword [0x006020a8]                ; [0x6020a8:8]=0
|    || |   0x00400af5      mov rdi, rax
|    || |   0x00400af8      call sym.imp.free                          ; void free(void *ptr)
|    || |   0x00400afd      mov dword [0x006020bc], 0                  ; [0x6020bc:4]=0
|    || |   0x00400b07      nop
|    || |   ; JMP XREF from 0x00400ab6 (sub.Which_Secret_do_you_want_to_wipe_a27)
|    || |   ; JMP XREF from 0x00400ad1 (sub.Which_Secret_do_you_want_to_wipe_a27)
|    || |   ; JMP XREF from 0x00400aec (sub.Which_Secret_do_you_want_to_wipe_a27)
|    ``-`-> 0x00400b08      mov rax, qword [local_8h]
|           0x00400b0c      xor rax, qword fs:[0x28]
|       ,=< 0x00400b15      je 0x400b1c
|       |   0x00400b17      call sym.imp.__stack_chk_fail              ; void __stack_chk_fail(void)
|       |   ; JMP XREF from 0x00400b15 (sub.Which_Secret_do_you_want_to_wipe_a27)
|       `-> 0x00400b1c      leave
\           0x00400b1d      ret

Renew secret

[0x00400780]> pdf @ sub.Which_Secret_do_you_want_to_renew_b1e 
/ (fcn) sub.Which_Secret_do_you_want_to_renew_b1e 330
|   sub.Which_Secret_do_you_want_to_renew_b1e ();
|           ; var int local_14h @ rbp-0x14
|           ; var int local_10h @ rbp-0x10
|           ; var int local_8h @ rbp-0x8
|           ; CALL XREF from 0x00400d86 (main)
|           0x00400b1e      push rbp
|           0x00400b1f      mov rbp, rsp
|           0x00400b22      sub rsp, 0x20
|           0x00400b26      mov rax, qword fs:[0x28]                   ; [0x28:8]=-1 ; '(' ; 40
|           0x00400b2f      mov qword [local_8h], rax
|           0x00400b33      xor eax, eax
|           0x00400b35      mov edi, str.Which_Secret_do_you_want_to_renew ; 0x400ec0 ; "Which Secret do you want to renew?"
|           0x00400b3a      call sym.imp.puts                          ; int puts(const char *s)
|           0x00400b3f      mov edi, str.1._Small_secret               ; 0x400e53 ; "1. Small secret"
|           0x00400b44      call sym.imp.puts                          ; int puts(const char *s)
|           0x00400b49      mov edi, str.2._Big_secret                 ; 0x400e63 ; "2. Big secret"
|           0x00400b4e      call sym.imp.puts                          ; int puts(const char *s)
|           0x00400b53      mov edi, str.3._Huge_secret                ; 0x400e71 ; "3. Huge secret"
|           0x00400b58      call sym.imp.puts                          ; int puts(const char *s)
|           0x00400b5d      lea rax, [local_10h]
|           0x00400b61      mov edx, 4
|           0x00400b66      mov esi, 0
|           0x00400b6b      mov rdi, rax
|           0x00400b6e      call sym.imp.memset                        ; void *memset(void *s, int c, size_t n)
|           0x00400b73      lea rax, [local_10h]
|           0x00400b77      mov edx, 4
|           0x00400b7c      mov rsi, rax
|           0x00400b7f      mov edi, 0
|           0x00400b84      mov eax, 0
|           0x00400b89      call sym.imp.read                          ; ssize_t read(int fildes, void *buf, size_t nbyte)
|           0x00400b8e      lea rax, [local_10h]
|           0x00400b92      mov rdi, rax
|           0x00400b95      call sym.imp.atoi                          ; int atoi(const char *str)
|           0x00400b9a      mov dword [local_14h], eax
|           0x00400b9d      mov eax, dword [local_14h]
|           0x00400ba0      cmp eax, 2                                 ; 2
|       ,=< 0x00400ba3      je 0x400be9
|       |   0x00400ba5      cmp eax, 3                                 ; 3
|      ,==< 0x00400ba8      je 0x400c1f
|      ||   0x00400baa      cmp eax, 1                                 ; 1
|     ,===< 0x00400bad      jne 0x400c52
|     |||   0x00400bb3      mov eax, dword [0x006020c0]                ; [0x6020c0:4]=0
|     |||   0x00400bb9      test eax, eax
|    ,====< 0x00400bbb      je 0x400be7
|    ||||   0x00400bbd      mov edi, str.Tell_me_your_secret:          ; 0x400e80 ; "Tell me your secret: "
|    ||||   0x00400bc2      call sym.imp.puts                          ; int puts(const char *s)
|    ||||   0x00400bc7      mov rax, qword [0x006020b0]                ; [0x6020b0:8]=0
|    ||||   0x00400bce      mov edx, 0x28                              ; '(' ; 40
|    ||||   0x00400bd3      mov rsi, rax
|    ||||   0x00400bd6      mov edi, 0
|    ||||   0x00400bdb      mov eax, 0
|    ||||   0x00400be0      call sym.imp.read                          ; ssize_t read(int fildes, void *buf, size_t nbyte)
|   ,=====< 0x00400be5      jmp 0x400c52
|   |||||   ; JMP XREF from 0x00400bbb (sub.Which_Secret_do_you_want_to_renew_b1e)
|  ,=`----> 0x00400be7      jmp 0x400c52
|  || |||   ; JMP XREF from 0x00400ba3 (sub.Which_Secret_do_you_want_to_renew_b1e)
|  || ||`-> 0x00400be9      mov eax, dword [0x006020b8]                ; [0x6020b8:4]=0
|  || ||    0x00400bef      test eax, eax
|  || ||,=< 0x00400bf1      je 0x400c1d
|  || |||   0x00400bf3      mov edi, str.Tell_me_your_secret:          ; 0x400e80 ; "Tell me your secret: "
|  || |||   0x00400bf8      call sym.imp.puts                          ; int puts(const char *s)
|  || |||   0x00400bfd      mov rax, qword [0x006020a0]                ; [0x6020a0:8]=0
|  || |||   0x00400c04      mov edx, 0xfa0                             ; 4000
|  || |||   0x00400c09      mov rsi, rax
|  || |||   0x00400c0c      mov edi, 0
|  || |||   0x00400c11      mov eax, 0
|  || |||   0x00400c16      call sym.imp.read                          ; ssize_t read(int fildes, void *buf, size_t nbyte)
|  ||,====< 0x00400c1b      jmp 0x400c52
|  ||||||   ; JMP XREF from 0x00400bf1 (sub.Which_Secret_do_you_want_to_renew_b1e)
| ,=====`-> 0x00400c1d      jmp 0x400c52
| ||||||    ; JMP XREF from 0x00400ba8 (sub.Which_Secret_do_you_want_to_renew_b1e)
| |||||`--> 0x00400c1f      mov eax, dword [0x006020bc]                ; [0x6020bc:4]=0
| |||||     0x00400c25      test eax, eax
| ||||| ,=< 0x00400c27      je 0x400c51
| ||||| |   0x00400c29      mov edi, str.Tell_me_your_secret:          ; 0x400e80 ; "Tell me your secret: "
| ||||| |   0x00400c2e      call sym.imp.puts                          ; int puts(const char *s)
| ||||| |   0x00400c33      mov rax, qword [0x006020a8]                ; [0x6020a8:8]=0
| ||||| |   0x00400c3a      mov edx, 0x61a80
| ||||| |   0x00400c3f      mov rsi, rax
| ||||| |   0x00400c42      mov edi, 0
| ||||| |   0x00400c47      mov eax, 0
| ||||| |   0x00400c4c      call sym.imp.read                          ; ssize_t read(int fildes, void *buf, size_t nbyte)
| ||||| |   ; JMP XREF from 0x00400c27 (sub.Which_Secret_do_you_want_to_renew_b1e)
| ||||| `-> 0x00400c51      nop
| |||||     ; JMP XREF from 0x00400bad (sub.Which_Secret_do_you_want_to_renew_b1e)
| |||||     ; JMP XREF from 0x00400be5 (sub.Which_Secret_do_you_want_to_renew_b1e)
| |||||     ; JMP XREF from 0x00400be7 (sub.Which_Secret_do_you_want_to_renew_b1e)
| |||||     ; JMP XREF from 0x00400c1b (sub.Which_Secret_do_you_want_to_renew_b1e)
| |||||     ; JMP XREF from 0x00400c1d (sub.Which_Secret_do_you_want_to_renew_b1e)
| `````---> 0x00400c52      mov rax, qword [local_8h]
|           0x00400c56      xor rax, qword fs:[0x28]
|       ,=< 0x00400c5f      je 0x400c66
|       |   0x00400c61      call sym.imp.__stack_chk_fail              ; void __stack_chk_fail(void)
|       |   ; JMP XREF from 0x00400c5f (sub.Which_Secret_do_you_want_to_renew_b1e)
|       `-> 0x00400c66      leave
\           0x00400c67      ret

漏洞利用

参考资料