We participated the APU BOH yesterday! It was quite fun for beginners, I think it was better compared to last year.
Scoreboard:
Here is some writeups of some reverse challenges!
Challenges
babyrev
Challenges file
We have two files given, one linux executable file (ELF), and one 7zip file which need password to extract it
Try running the babyrev
can see it need an argument:
./babyrev
Need exactly one argument.
./babyrev asdf
Incorrect.
We can see it say incorrect, can guess the correct argument will be the password of the 7zip file
Running strings
can see got a very long string:
strings babyrev
/lib64/ld-linux-x86-64.so.2
puts
__cxa_finalize
__libc_start_main
libc.so.6
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
u3UH
[]A\A]A^A_
Need exactly one argument.
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
Looks like base64, tried to decode it but failed, lets open it with decompiler - Ghidra
undefined8 FUN_00101139(int param_1,long param_2)
{
undefined8 uVar1;
int local_14;
if (param_1 == 2) {
local_14 = 0;
while (((&DAT_00102028)[local_14] != '\0' &&
(*(char *)((long)local_14 + *(long *)(param_2 + 8)) != '\0'))) {
if ((char)(&DAT_00102028)[local_14] + -0xf !=
(int)*(char *)((long)local_14 + *(long *)(param_2 + 8))) {
puts("Incorrect.");
return 1;
}
local_14 = local_14 + 1;
}
puts("Correct!");
uVar1 = 0;
}
else {
puts("Need exactly one argument.");
uVar1 = 0xffffffff;
}
return uVar1;
}
Can see it compare our argument param_2 + 8
with the long string DAT_00102028
The comparision happen at this line:
if ((char)(&DAT_00102028)[local_14] + -0xf != (int)*(char *)((long)local_14 + *(long *)(param_2 + 8))) {
puts("Incorrect.");
return 1;
}
Basically means the ASCII value of the long string minus 0xf if not equal our argument then it prints incorrect
Also means the long string minus 0xf is the correct argument we need!!
Wrote a simple python script to do this:
text = b"TzgBGgWNsQLHRLY..."
for t in text:
print(chr(t-0xf),end='')
Output:
EkX38XH?dB=9C=JG2D)$[2Ke6T_AT;F*g%DBYb'f;9b?Xi%39'FIV%gSFA=$eWXW;R\J>aRdi?Y6_dX*)&%7KI9>I7>kIYe>\S=4>C)W<S&#b\SGa7I'TdSK)W_W($8$#(CK>)8V$TD823#j(iYjG2i8)=8(*<5ic==eB_aDaY2CBAJgF%E5<$dS%Ci[;2<;%?U;EK__=_cHY_hY5Y93'W64d9J%h7#48FD=faKUf?e<7G'G%a7F8fe;F>(&fa$fU746^=8f6ggb5A&&DGE_=&j\3g(_?=if&XeT_k'5k4RKb*^?fcGfB_I3fDg[AdBK?E^eEk#D*((k548Y3dgh?Aa_5eH8(8EkCX%Ccf[$Rg>d&eKFI5bBhD9X8==h722#>jR^ka[R(Y3i\$c'D>RGC2<UgC34237BAiIfB^DY$E^[>V3US%h7c4bVCBbU&T9=U'hK#HXK[X5FVjUf_KHAJ%T_gRHJd'[939EX$TJ)_>a?)$%H<%B;Sd7?a3=aH$'g7IEJR_kIkRIkK=#V<_d5(Df;XWjCD<Y%GeY*UU3%FB3>%3iF8>c==U_^eJ#3j9=U4&eXG94^'7_bTD548=eS_Rcd&=AE>))$AFeBX$&hS2\4\?8G67D&gcS?DdR*EK^?XT*D5j>2b<iieiCIG3X'*(j9;$cT#k3e\ekW6cJDJ7e76DG4ABHkD7Sg&;<YTc%$SbcIB7EHEY7_EbEfIJe87eVki78WBW;RHR*H>&X\$$9DGH=f4CUJT2g$IaV[EA7D9H'E$;c%j[J;?[UBKbJhW=&#&>b$)S$SB28;^XBE_2'D#&&4>6)*cRDhhX$\Dc$JjRAK)<VgC)XFRdk_[2%(J5^d9[U#HHfS$GA&D?j>Ta$KC[?kdiG[Y^'8V)hdJT(kWJD^K>GH;'kA<>#iYaS#W3I'G([Rb&*B4c4$JJIE5=&j>*4>=S(=X(c$;<d5UG9=&RbXi_kJK5A<;ASj\(*=T)=i34^FK\(7Egb3[>#)R2$H2Kf7FSSB%7<?<7RX3&XW\3%EW<D9EFA27J>HDRAdT3Sb5>W)$c)^d$F;<6*^YU3FjGA;fec#YJ>W$IiWd5hG_9(^&6<k[ka9%KER4^bUY?6Ek48$#h4e=b345kbc9';93ITKFHVe8Kh&9_*[>)S?)h)*6%U%)\ak3#>[5D=53aX2g9FKT=T'87_$)I>7dj^B%)K%HB5jh)g\H(3*9a6&_U#4A^6GVg^*G4f(<*86BXhBaI>8SY#KHbb^[7)AERgh#djaB#4&bVi#ai8)EK7=a5fUG9Vc3[)KIF%>KeA'X>R_aa7DD>ASY*Ce4B(US4)Rf4[Bif=>GS6*R(5C^2H48_7kJi>g=;>&fId\fj%j#eI?RG%G4WfA^9C>%da\#A^Xc2'32##)8_^_bCif;f\kG7I)WC3BRd>gg7hKKWD*eB>&dEYI2)\&G;kJDaJhKK=cWUHiDKR)beUc8*=C4TIkKIadR78Dg%&B7c#a&^#^W)[63^%*S;>_&5[ACJDe*2>kJRXVUEA=B9IacIgIXa$?%c#89>f6#4d44'Ji*h;<9FEkS#IbgTS6?6#*T7H;BF%#%H2'dghKa#(6[Vj\&k$gA?H#XFdI(9(T?;2b;Ha'^WjE=?8K\)BUV4)<\R_&W&3A>$S_ibX__##(Bb'%d'bV$<D<W9I*Ed4fB;c6<Cb)X65Jb$[I2[)<U)&6=GGB53[^2b?=eaJRV3kH43k#^eBB*3h=kAU<)>fgR%Cf7>F&8W4%BKe3TX33BDgV2ef3V[&k*'#T<(9Uc7(G47k9&XeaiF'=)89\IfD%GY?d74?Da7<89?\%_eiSi9fa#IH5TBi;g_T7?G2KfbK%$#)$=4YAae$4<_*$*A7\ec6fU6'#$);&2a\&HK=2h<A_d&W)Ad6hRSG__;f%C*=9>2iJ4\eG\=BDVYURiT8dG5JVVYb<j9VfF7K[?I\5B)>T>^b6J$6IA9JeAHSiaE3Yb9$4KSWAT$B2%SUb?#ERR['[eC&2<A9ISee5A5jU=>d4U>7hU#$7;$%g36aT8RW;<)I9[[W4
The output looks like some weird encryption but it is not I tried to decode
It is the password of the 7zip file, just copy & paste it you will get a flag.txt
file
Flag
BOH21{4lw4y5_u53_57r0nk_p455w0rd_;)_912429}
The Locker
Challenge files
An ELF file also, open it with Ghidra
The main
function:
int main(void)
{
int iVar1;
long lVar2;
size_t sVar3;
ulong uVar4;
long in_FS_OFFSET;
int input;
int i;
char input2 [32];
char answer [32];
char key2 [32];
char mainMenu1 [64];
char mainMenu2 [64];
char mainMenu3 [64];
long local_20;
local_20 = *(long *)(in_FS_OFFSET + 0x28);
mainMenu1._0_8_ = 0x656d6f636c65570a;
mainMenu1._8_8_ = 0x20656874206f7420;
mainMenu1._16_8_ = 0x212172656b636f4c;
mainMenu1._24_8_ = 0xa21;
mainMenu1._32_8_ = 0;
mainMenu1._40_8_ = 0;
mainMenu1._48_8_ = 0;
mainMenu1._56_8_ = 0;
mainMenu2._0_8_ = 0x6d2065766947207e;
mainMenu2._8_8_ = 0x626d756e20612065;
mainMenu2._16_8_ = 0x203a7265;
mainMenu2._24_8_ = 0;
mainMenu2._32_8_ = 0;
mainMenu2._40_8_ = 0;
mainMenu2._48_8_ = 0;
mainMenu2._56_8_ = 0;
mainMenu3._0_8_ = 0x6d2065766947207e;
mainMenu3._8_8_ = 0x6972747320612065;
mainMenu3._16_8_ = 0x203a676e;
mainMenu3._24_8_ = 0;
mainMenu3._32_8_ = 0;
mainMenu3._40_8_ = 0;
mainMenu3._48_8_ = 0;
mainMenu3._56_8_ = 0;
key2._0_8_ = 0x6a567933304a4d40;
key2._8_8_ = 0x485d7b7436465d31;
key2._16_8_ = 0x61324e5d71316c32;
key2._24_8_ = 0x7f703169;
lVar2 = ptrace(PTRACE_TRACEME,0,1,0);
if (lVar2 < 0) {
puts("Third Party Application has been detected!!!");
iVar1 = 0;
}
else {
puts(
" ...,NDDDDDN,...\n .IDDDDDDDDDD87.\n ...NDDDD=...,NDDDD..\n ...ZDDD... ..DDDD..\n ...DDD$. ........DDD,.\n ...DDD,.. ...DDD~..\n ..,DDD... ...DDD+..\n .,DDD,... .. .DDDI...\n...:=?DDDI??????????DDDZ~:.....\n...DDDDDDDDDDDD8DDDDDDDDDDDN...\n...DDDDN....$D.?DDZ....NDDDN...\n...DDDDN.ON.$D...DZ.N8.NDDDN...\n...DDDDN....$DDI.N$....NDDDN...\n...DDD8DDDDDD..DDDDD$$DDDDDN...\n...DDDDN...ID...ND=~..~DDDDN...\n...DDDDN.O. ...DDD,,,,.NDDDN...\n...DDDDDDDDDDDDI.D8IND?DDDDN...\n...DDDDN... $D...DZ.NDDDDDDN...\n...DDDDN.ON $DDDDDO~N8.NDDDN...\n ..DDDDN....$D.?D..?D..NDDDN.. \n .NDDDDDDDDDDDDDDDDDDDDDDDN. "
);
printf("%s",mainMenu1);
puts("~ Give me the right input and I shall give you what you wanted...");
printf("%s",mainMenu2);
while( true ) {
iVar1 = __isoc99_scanf(&DAT_00102316,&input);
if (iVar1 == 1) break;
puts("\nYou did not enter a valid number");
printf("%s",mainMenu2);
__isoc99_scanf(&DAT_00102312);
}
printf("%s",mainMenu3);
__isoc99_scanf(&DAT_0010231a,input2);
strcpy(answer,input2);
i = 0;
while( true ) {
uVar4 = SEXT48(i);
sVar3 = strlen(input2);
if (sVar3 - 1 < uVar4) break;
input2[i] = (char)input - 0x37U ^ input2[i];
if (input2[i] != key2[i]) {
puts("\n~ Looks like you are not the right person");
iVar1 = -1;
goto LAB_00101568;
}
i = i + 1;
}
puts("\n~ Well done, perhaps the wisdom have spoken to yourself");
printf("%s",answer);
iVar1 = 0;
}
LAB_00101568:
if (local_20 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return iVar1;
}
We focus on the comparision part:
iVar1 = __isoc99_scanf(&DAT_00102316,&input);
if (iVar1 == 1) break;
puts("\nYou did not enter a valid number");
...
...
while( true ) {
uVar4 = SEXT48(i);
sVar3 = strlen(input2);
if (sVar3 - 1 < uVar4) break;
input2[i] = (char)input - 0x37U ^ input2[i];
if (input2[i] != key2[i]) {
puts("\n~ Looks like you are not the right person");
iVar1 = -1;
goto LAB_00101568;
}
i = i + 1;
}
puts("\n~ Well done, perhaps the wisdom have spoken to yourself");
printf("%s",answer);
iVar1 = 0;
As you can see it just XOR with a random number, then check is it equal to key2!
Wrote down the equation is like this:
key2 = (number - 0x37) ^ flag
flag = key2 ^ (number - 0x37)
We know the flag format start with BOH21
, therefore we can calculate the XOR key and decrypt the flag:
from pwn import *
# Copy the value from Ghidra
key2 = p64(0x6a567933304a4d40)
key2 += p64(0x485d7b7436465d31)
key2 += p64(0x61324e5d71316c32)
key2 += p64(0x7f703169)
# B = key2[0] ^ (number - 0x37)
xor_key = key2[0] ^ ord('B')
for k in key2:
print(chr(k^xor_key),end='')
# BOH21{Th3_D4vy_J0n3s_L0ck3r}
Flag
BOH21{Th3_D4vy_J0n3s_L0ck3r}
Not So Difficult
Challenge files
Also an ELF file, running strings
on it we can see it contains some python libraries:
strings NotSoDifficult
...
...
...
blib-dynload/binascii.cpython-38-x86_64-linux-gnu.so
blib-dynload/grp.cpython-38-x86_64-linux-gnu.so
blib-dynload/math.cpython-38-x86_64-linux-gnu.so
blib-dynload/mmap.cpython-38-x86_64-linux-gnu.so
blib-dynload/pyexpat.cpython-38-x86_64-linux-gnu.so
blib-dynload/readline.cpython-38-x86_64-linux-gnu.so
blib-dynload/resource.cpython-38-x86_64-linux-gnu.so
blib-dynload/select.cpython-38-x86_64-linux-gnu.so
blib-dynload/termios.cpython-38-x86_64-linux-gnu.so
blib-dynload/unicodedata.cpython-38-x86_64-linux-gnu.so
blib-dynload/zlib.cpython-38-x86_64-linux-gnu.so
...
...
...
This is a indicator that this executable is produced by Pyinstaller
We need to “Uninstall” it back to python file, to do this just need pyinstxtractor.py
Run it with python3 will extract back the python file:
python3 pyinstxtractor.py NotSoDifficult
[+] Processing NotSoDifficult
[+] Pyinstaller version: 2.1+
[+] Python version: 38
[+] Length of package: 9386872 bytes
[+] Found 66 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: pyi_rth_pkgutil.pyc
[+] Possible entry point: pyi_rth_multiprocessing.pyc
[+] Possible entry point: pyi_rth_inspect.pyc
[+] Possible entry point: BOHChall3.pyc
[+] Found 223 files in PYZ archive
[+] Successfully extracted pyinstaller archive: NotSoDifficult
You can now use a python decompiler on the pyc files within the extracted directory
Look at the extracted folder, we can see there is a BOHChall3.pyc
file
ls NotSoDifficult_extracted
BOHChall3.pyc lib-dynload libpython3.8.so libz.so.1 pyiboot01_bootstrap.pyc pyimod04_ctypes.pyc
PYZ-00.pyz libcrypto.so.1.1 libreadline.so.8 pyi_rth_inspect.pyc pyimod01_os_path.pyc struct.pyc
PYZ-00.pyz_extracted libffi.so.7 libssl.so.1.1 pyi_rth_multiprocessing.pyc pyimod02_archive.pyc
base_library.zip liblzma.so.5 libtinfow.so.6 pyi_rth_pkgutil.pyc pyimod03_importers.pyc
That is compiled python code, can decompile it using uncompyle6
# uncompyle6 BOHChall3.pyc
# uncompyle6 version 3.7.4
# Python bytecode 3.8 (3413)
# Decompiled from: Python 3.8.5 (default, Jan 27 2021, 15:41:15)
# [GCC 9.3.0]
# Embedded file name: BOHChall3.py
import base64, string
def convert(input, index):
b = input.encode('UTF-8')
if index == 0:
e = base64.b16encode(b)
d = e.decode('UTF-8')
if d != '31543173':
return 0
if index == 4:
e = base64.b32encode(b)
d = e.decode('UTF-8')
if d != 'KMYW24A=':
return 0
if index == 8:
e = base64.b64encode(b)
d = e.decode('UTF-8')
if d != 'bDM0cw==':
return 0
elif index == 12:
e = base64.a85encode(b)
d = e.decode('UTF-8')
if d != '<+n+1':
return 0
else:
return 1
def checkInput(input):
x = 0
j = 0
for i in range(x, len(input), 4):
x = i
if convert(input[x:x + 4], x) == 0:
return 0
return 1
usrInput = input('Enter password for authentication: ')
i = 0
if usrInput:
if len(usrInput) == 16:
if checkInput(usrInput) == 0:
print('Wrong Password')
else:
print('Correct, the flag is the password')
else:
print('Wrong Password')
# okay decompiling BOHChall3.pyc
As you can see, it is just base encoding, wrote a simple python script to decode it:
import base64
flag = base64.b16decode('31543173')
flag += base64.b32decode('KMYW24A=')
flag += base64.b64decode('bDM0cw==')
flag += base64.a85decode('<+n+1')
print(flag)
# 1T1sS1mpl34sTh4t
Flag
BOH21{1T1sS1mpl34sTh4t}
Summary
I think it is a good CTF for beginners, but notice some challenges with higher points but is easier than the lower points one. Also some challenges are similar just different title, therefore I think can improve the quality of the challenges and maybe all challenges put same points and decay by solves will be more fair for players.