Defcon CTF Quals 2013 – \xff\xe4\xcc 3 (linked)

typedef struct _llist {
struct _llist *next;
uint32_t tag;
char data[100];


register char *answer;
char *(*func)();
llist *head;

func = (char *(*)(llist *))userBuf;
answer = (char *)(*func)(head);

Write me shellcode that traverses the randomly generated linked list, looking for a node with a tag 0x41414100, and returns a pointer to the data associated with that tag, such that the call to send_string will output the answer.

Running at OR

Summary: x86 shellcode golfing.

Alright, what could be easier?

55                push ebp
89E5              mov ebp, esp
8B45 08           mov eax, [ebp + 8]  ; get first arg
8178 04 00414141  cmp dword ptr [eax + 4], 41414100h  ; eax->tag == 0x41414100 ?
74 04             je _found
8B00              mov eax, [eax]  ; eax = eax->next
EB F3             jmp _loopAgain
83C0 08           add eax, 8  ; eax = &eax->data
C9                leave
C3                ret

We’ve got our gorgeous shellcode:


Let’s send it in.

C:\Users\vos>nc 22222
List built.  Send me your shellcode.  Max size: 16

Oh dayum! Ours is 24. Let’s see what we can cut.

; first of all, fuck the prologue
59                pop ecx  ; save return address in ecx
5E                pop esi  ; get argument (pointer to list) in esi
AD                lodsd    ; == mov eax, [esi]
66:8178 05 4141   cmp word ptr [eax+5], 4141h   ; we have to sacrifice two bytes of the tag for 1 byte less code
50                push eax ; put eax back into stack for 'pop esi'
75 F5             jne _loopAgain
04 08             add al, 8  ; eax = &eax->data
FFE1              jmp ecx    ; jump back to return address. We don't care about stack frames.

16 bytes exactly, phew.

F:\>nc 22222 < shellcode
List built.  Send me your shellcode.  Max size: 16
The key is: Who says ESP isn't general purpose!?!?


  1. What assembler did you use? Both nasm and yasm do not accept the “WORD PTR” syntax and assemble “pop ecx” as \x66\x59 instead of \x59. Did you hand massage the resulting shellcode?

      • vos on June 17, 2013 at 15:20
      • Reply

      Actually I hand-crafted the shellcode in OllyDbg using built-in assembler, but any assembler should generate the exact same bytecode.

      Looks like your NASM assembles in 16-bit mode by default.
      Add ‘bits 32‘ at the top of your .asm.

    1. nasm is very good for shellcodes!

      1. for x64 you need to put “BITS 64” directive in file
      2. don’t use PTR word (just mov dword [rax], 0x1234)

Leave a Reply

Your email address will not be published.