Solution to nc3 Tys Tys
name:
Tys Tys
category:
reverse
points:
n/a
Writeup
The last problem in the danish police CTF was Tys Tys and we got a stripped elf binary named tys_tys and this danish text:
Fredag morgen kl. 7 mødte professor Tournesol ind på laboratoriet, hvor han arbejdede. Bag
arbejdsbordet med softice-centrifugen fandt han en stærkt blødende professor Lennardo. Lennardo
var såret, og gerningsmanden var flygtet. Før Lennardo udåndede, nåede han at remse en hemmelig
cifferkode op: 3,2,0,4,2,2,5,0,6,7,10,9,11,2,1,11,0,7,10,6,10,8,9,0,6,7,10,9,11,2,1,11. Og med
sit livs sidste kræftanstrengelser pegede han mod skuffe 3, hvor et USB-medie lå gemt. I skuffen
lå ligeledes en seddel med teksten: "Jeg har for en sikkerhedsskyld nullet programmet."
På USB-mediet fandt Tournesol et program, og programmet gemte på en besked(flaget), der kunne
redde verdenen!
Decompiling this in IDA gave us the following c code:
/* This file has been generated by the Hex-Rays decompiler.
Copyright (c) 2007-2015 Hex-Rays <info@hex-rays.com>
Detected compiler: GNU C++
*/
#include <defs.h>
//-------------------------------------------------------------------------
// Function declarations
int init_proc();
// ssize_t recv(int fd, void *buf, size_t n, int flags);
// int putchar(int c);
// char *strcpy(char *dest, const char *src);
// uint16_t htons(uint16_t hostshort);
// ssize_t send(int fd, const void *buf, size_t n, int flags);
// int snprintf(char *s, size_t maxlen, const char *format, ...);
// int close(int fd);
// struct hostent *gethostbyname(const char *name);
// void *malloc(size_t size);
// __int64 ptrace(enum __ptrace_request request, ...);
// void bzero(void *s, size_t n);
// int connect(int fd, const struct sockaddr *addr, socklen_t len);
// int __fastcall _cxa_finalize(_QWORD); weak
// int socket(int domain, int type, int protocol);
int sub_930();
int sub_9C0();
int sub_A00();
__int64 sub_A30();
void *sub_A9C();
_BYTE *sub_AEB();
const char *sub_BF0();
__int64 __fastcall main(__int64 a1, char **a2, char **a3);
void __fastcall init(unsigned int a1, __int64 a2, __int64 a3);
void term_proc();
// int ITM_deregisterTMCloneTable(void); weak
// int _gmon_start__(void); weak
// int Jv_RegisterClasses(void); weak
//-------------------------------------------------------------------------
// Data declarations
_UNKNOWN unk_E20; // weak
__int64 (__fastcall *off_201D68[3])() = { &sub_A00, &sub_A30, &sub_9C0 }; // weak
__int64 (__fastcall *off_201D78)() = &sub_9C0; // weak
_UNKNOWN unk_201D80; // weak
void *off_202008 = &off_202008; // weak
char byte_202010; // weak
_UNKNOWN unk_202017; // weak
// extern _UNKNOWN __cxa_finalize; weak
//----- (0000000000000858) ----------------------------------------------------
int init_proc()
{
int (**v0)(void); // rax@1
v0 = &_gmon_start__;
if ( &_gmon_start__ )
LODWORD(v0) = _gmon_start__();
return (unsigned __int64)v0;
}
// 20205C: using guessed type int _gmon_start__(void);
//----- (0000000000000900) ----------------------------------------------------
#error "906: positive sp value has been found (funcsize=3)"
//----- (0000000000000930) ----------------------------------------------------
int sub_930()
{
int (**v0)(void); // rax@1
v0 = (int (**)(void))(&unk_202017 - (_UNKNOWN *)&byte_202010);
if ( (unsigned __int64)(&unk_202017 - (_UNKNOWN *)&byte_202010) > 0xE )
{
v0 = &ITM_deregisterTMCloneTable;
if ( &ITM_deregisterTMCloneTable )
LODWORD(v0) = ITM_deregisterTMCloneTable();
}
return (unsigned __int64)v0;
}
// 202010: using guessed type char byte_202010;
// 202058: using guessed type int ITM_deregisterTMCloneTable(void);
//----- (00000000000009C0) ----------------------------------------------------
int sub_9C0()
{
int result; // eax@4
if ( !byte_202010 )
{
if ( &__cxa_finalize )
_cxa_finalize(off_202008);
result = sub_930();
byte_202010 = 1;
}
return result;
}
// 8E8: using guessed type int __fastcall _cxa_finalize(_QWORD);
// 202008: using guessed type void *off_202008;
// 202010: using guessed type char byte_202010;
//----- (0000000000000A00) ----------------------------------------------------
int sub_A00()
{
if ( unk_201D80 && &Jv_RegisterClasses )
Jv_RegisterClasses();
return 0;
}
// 202060: using guessed type int Jv_RegisterClasses(void);
//----- (0000000000000A30) ----------------------------------------------------
__int64 sub_A30()
{
__int64 result; // rax@3
signed int v1; // [sp+Ch] [bp-4h]@1
v1 = 0;
if ( !ptrace(0, 0LL, 1LL, 0LL) )
v1 = 2;
result = ptrace(0, 0LL, 1LL, 0LL);
if ( result == -1 )
result = (unsigned int)(3 * v1);
return result;
}
//----- (0000000000000A9C) ----------------------------------------------------
void *sub_A9C()
{
return &unk_E20;
}
//----- (0000000000000AEB) ----------------------------------------------------
_BYTE *sub_AEB()
{
_BYTE *buf; // ST10_8@1
struct hostent *v1; // ST18_8@1
int fd; // ST08_4@1
_BYTE *result; // rax@1
__int64 v4; // rcx@1
struct sockaddr addr; // [sp+20h] [bp-20h]@1
__int64 v6; // [sp+38h] [bp-8h]@1
v6 = *MK_FP(__FS__, 40LL);
buf = malloc(3uLL);
v1 = gethostbyname("45.63.119.180");
fd = socket(2, 1, 0);
addr.sa_family = 2;
*(_WORD *)&addr.sa_data[0] = htons(0x115Cu);
*(_DWORD *)&addr.sa_data[2] = **(_DWORD **)v1->h_addr_list;
bzero(&addr.sa_data[6], 8uLL);
connect(fd, &addr, 0x10u);
send(fd, "?\n", 2uLL, 0);
buf[(signed int)recv(fd, buf, 3uLL, 0)] = 0;
close(fd);
result = buf;
v4 = *MK_FP(__FS__, 40LL) ^ v6;
return result;
}
//----- (0000000000000BF0) ----------------------------------------------------
const char *sub_BF0()
{
const char *result; // rax@1
__int64 v1; // rdx@1
result = "PRATEZ";
v1 = *MK_FP(__FS__, 40LL) ^ *MK_FP(__FS__, 40LL);
return result;
}
//----- (0000000000000C7C) ----------------------------------------------------
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
const char *v3; // rax@1
const char *v4; // rax@1
const char *v5; // rax@1
__int64 result; // rax@4
__int64 v7; // rcx@4
signed int i; // [sp+0h] [bp-50h]@1
char dest; // [sp+7h] [bp-49h]@1
char v10; // [sp+Ah] [bp-46h]@1
char v11; // [sp+Dh] [bp-43h]@1
char s[13]; // [sp+13h] [bp-3Dh]@1
__int64 v13; // [sp+20h] [bp-30h]@1
__int64 v14; // [sp+28h] [bp-28h]@1
__int64 v15; // [sp+30h] [bp-20h]@1
__int64 v16; // [sp+38h] [bp-18h]@1
__int64 v17; // [sp+48h] [bp-8h]@1
v17 = *MK_FP(__FS__, 40LL);
v3 = (const char *)sub_A9C();
strcpy(&dest, v3);
v4 = sub_AEB();
strcpy(&v10, v4);
v5 = sub_BF0();
strcpy(&v11, v5);
snprintf(s, 0xDuLL, "%s%s%s", &dest, &v10, &v11);
v13 = 0LL;
v14 = 0LL;
v15 = 0LL;
v16 = 0LL;
for ( i = 0; i <= 31; ++i )
putchar(s[*((_BYTE *)&v13 + i)]);
putchar(10);
result = 0LL;
v7 = *MK_FP(__FS__, 40LL) ^ v17;
return result;
}
// C7C: using guessed type char s[13];
//----- (0000000000000D90) ----------------------------------------------------
void __fastcall init(unsigned int a1, __int64 a2, __int64 a3)
{
__int64 v3; // r13@1
signed __int64 v4; // rbp@1
__int64 v5; // rbx@2
v3 = a3;
v4 = &off_201D78 - off_201D68;
init_proc();
if ( v4 )
{
v5 = 0LL;
do
((void (__fastcall *)(_QWORD, __int64, __int64))off_201D68[v5++])(a1, a2, v3);
while ( v4 != v5 );
}
}
// 201D68: using guessed type __int64 (__fastcall *off_201D68[3])();
// 201D78: using guessed type __int64 (__fastcall *off_201D78)();
//----- (0000000000000E04) ----------------------------------------------------
void term_proc()
{
;
}
#error "There were 1 decompilation failure(s) on 12 function(s)"
Some manual analysis gave us that the function sub_A9C always returns the string “_L3”.
The server at 45.63.119.180:4444 that was contacted returned the string “WND” when a ? was sent in, and “Forkert” for everything else, the server also crashed after the challenge had been running for a hour.
The last part was produced from the function sub_BF0 that returned “PRATEZ”.
Using the professors list of numbers as indexes into the string we could produce the flag:
<?php
$key =
array(3,2,0,4,2,2,5,0,6,7,10,9,11,2,1,11,0,7,10,6,10,8,9,0,6,7,10,9,11,2,1,11);
$str = "_L3WNDPRATEZ";
for($i = 0; $i < count($key); $i++){
echo $str[$key[$i]];
}
?>
flag was: W3_N33D_PRETZ3LZ_REPEAT_PRETZ3LZ