Sheb-Teth (LayerOne 2017 CTF)

We get a binary! I don't remember any more hints to it than just that. There was flavor text, but I've lost it.

If we strings Sheb-Teth.bin we'll see some helpfully embedded strings to guide us in the right direction:

        [snip]
        ...
        [^_]
        [^_]
        #.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.
        . @emptymonkey            https://github.com/emptymonkey            2017-03-10 #
        #                                                                              .
        . Welcome to the LayerOne 2017 CTF "Sheb-Teth" RE challenge.                   #
        # There are six flags. flag_0, flag_1, ..., flag_5.                            .
        . Each flag is in a uuid format. e.g. c8da2132-382e-11e7-9862-507b9d8156b4     #
        # When prompted, enter the flag you would like to test.                        .
        . This program will tell you if the flag you entered is a valid flag.          #
        # (You know how to speak R'lyehian, right?!)                                   .
        . Enjoy!                                                                       #
        .#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#
        uln sheb teth  n'ghaoth  sll'ha throd
        mglw'nafh fhthagn-ngah cf'ayak 'vulgtmm vugtlag'n
        mnahn' r'luh
        ...
        [snip]
    

Bold added by me, for emphasis. It probably would have been a good idea to check out that github link, but I totally tunnel vision'd over it at first.

So, we know this binary is what we'll be getting used to for all six flags in Sheb-Teth.

Flag 0

Continuing to look through strings output we'll find f36c454e-3831-11e7-a8b5-3fb45ccb41a5, and if we try to run the program with that as input... we'll find it quits with an error message:

Unclean mortal! Do not return until you wield *true* power!!

.. wtf, right?

Opening this up in radare2 and looking at the start of sym.main: (for those playing along at home, aaa to look for functions, then pdf @ sym.main to print the disassembled function at the symbol main)

            ;-- main:
    / (fcn) sym.main 654
    |   sym.main ();
    |           ; var int local_38h @ ebp-0x38
    |           ; var int local_34h @ ebp-0x34
    |           ; var int local_30h @ ebp-0x30
    |           ; var int local_2ch @ ebp-0x2c
    |           ; var int local_28h @ ebp-0x28
    |           ; var int local_24h @ ebp-0x24
    |           ; var int local_20h @ ebp-0x20
    |           ; var int local_1ch @ ebp-0x1c
    |           ; var int local_18h @ ebp-0x18
    |           ; var int local_14h @ ebp-0x14
    |           ; var int local_10h @ ebp-0x10
    |           ; var int local_ch @ ebp-0xc
    |           ; var int local_4h_2 @ ebp-0x4
    |           ; var int local_4h @ esp+0x4
    |              ; DATA XREF from 0x08048837 (entry0)
    |           0x0804891b      8d4c2404       lea ecx, [local_4h]
    |           0x0804891f      83e4f0         and esp, 0xfffffff0
    |           0x08048922      ff71fc         push dword [ecx - 4]
    |           0x08048925      55             push ebp
    |           0x08048926      89e5           mov ebp, esp
    |           0x08048928      51             push ecx
    |           0x08048929      83ec34         sub esp, 0x34               ; '4'
    |           0x0804892c      c745f08ca404.  mov dword [local_10h], str.uln_sheb_teth__n_ghaoth__sll_ha_throd
    |           0x08048933      c745ecb4a404.  mov dword [local_14h], str.mglw_nafh_fhthagn_ngah_cf_ayak__vulgtmm_vugtlag_n
    |           0x0804893a      c745e8e6a404.  mov dword [local_18h], str.mnahn__r_luh
    |           0x08048941      c745e4f4a404.  mov dword [local_1ch], str.r_luh_chtenff__sll_ha_syha_h__y_hah
    |           0x08048948      c745e018a504.  mov dword [local_20h], str.n_ghft_hlirgh_lloig__shuggoth__zhro
    |           0x0804894f      c745dc3ca504.  mov dword [local_24h], str.ch_goka_gotha__uaaah
    |           0x08048956      c745d8000000.  mov dword [local_28h], 0
    |           0x0804895d      c745f4000000.  mov dword [local_ch], 0
    |           0x08048964      e847fdffff     call sym.imp.getuid         ; uid_t getuid(void)
    |           0x08048969      85c0           test eax, eax
    |       ,=< 0x0804896b      7421           je 0x804898e
    |       |   0x0804896d      a1a8b10408     mov eax, dword obj.stderr   ; loc.stderr ; [0x804b1a8:4]=0x3a434347 ; "GCC: (Debian 4.9.2-10) 4.9.2"
    |       |   0x08048972      50             push eax
    |       |   0x08048973      6a3d           push 0x3d                   ; '=' ; '='
    |       |   0x08048975      6a01           push 1                      ; "ELF\x01\x01\x01"
    |       |   0x08048977      6854a50408     push str.Unclean_mortal__Do_not_return_until_you_wield__true__power___n ; 0x804a554 ; "Unclean mortal! Do not return until you wield *true* power!!\n"
    |       |   0x0804897c      e84ffdffff     call sym.imp.fwrite         ; size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)
    |       |   0x08048981      83c410         add esp, 0x10
    |       |   0x08048984      83ec0c         sub esp, 0xc
    |       |   0x08048987      6aff           push 0xffffffffffffffff
    |       |   0x08048989      e8a2fdffff     call sym.imp.exit           ; void exit(int status)
    |       |      ; JMP XREF from 0x0804896b (sym.main)
    |       `-> 0x0804898e      83ec08         sub esp, 8
    |           0x08048991      6a01           push 1                      ; "ELF\x01\x01\x01"
    |           0x08048993      6a25           push 0x25                   ; '%' ; '%'
    |           0x08048995      e876feffff     call sym.imp.calloc         ; void *calloc(size_t nmeb, size_t size)
    |           0x0804899a      83c410         add esp, 0x10
    |           0x0804899d      8945d4         mov dword [local_2ch], eax
    |           0x080489a0      837dd400       cmp dword [local_2ch], 0
    |       ,=< 0x080489a4      7530           jne 0x80489d6
    |       |   0x080489a6      e8d5fdffff     call sym.imp.__errno_location
    |       |   0x080489ab      8b00           mov eax, dword [eax]
    |       |   0x080489ad      c745d0ffffff.  mov dword [local_30h], 0xffffffff
    |       |   0x080489b4      8945cc         mov dword [local_34h], eax
    |       |   0x080489b7      c745c892a504.  mov dword [local_38h], str.calloc__d___d_
    |       |   0x080489be      83ec0c         sub esp, 0xc
    |       |   0x080489c1      6a01           push 1                      ; "ELF\x01\x01\x01"
    |       |   0x080489c3      6a25           push 0x25                   ; '%' ; '%'
    |       |   0x080489c5      ff75c8         push dword [local_38h]
    |       |   0x080489c8      ff75cc         push dword [local_34h]
    |       |   0x080489cb      ff75d0         push dword [local_30h]
    |       |   0x080489ce      e81dfdffff     call sym.imp.error
    |       |   0x080489d3      83c420         add esp, 0x20
    |       |      ; JMP XREF from 0x080489a4 (sym.main)
    |       `-> 0x080489d6      83ec08         sub esp, 8
    |           0x080489d9      ff75f0         push dword [local_10h]
    |           0x080489dc      68a1a50408     push str._n_s_n             ; 0x804a5a1 ; "\n%s\n"
    |           0x080489e1      e88afcffff     call sym.imp.printf         ; int printf(const char *format)
    |           0x080489e6      83c410         add esp, 0x10
    |           0x080489e9      83ec08         sub esp, 8
    |           0x080489ec      ff75ec         push dword [local_14h]
    |           0x080489ef      68a6a50408     push str._n_s_n_            ; 0x804a5a6 ; "\n%s\n> "
    |           0x080489f4      e877fcffff     call sym.imp.printf         ; int printf(const char *format)
    |           0x080489f9      83c410         add esp, 0x10
    |           0x080489fc      a1acb10408     mov eax, dword obj.stdin    ; [0x804b1ac:4]=0x65442820 ; " (Debian 4.9.2-10) 4.9.2"
    |           0x08048a01      83ec04         sub esp, 4
    |           0x08048a04      50             push eax
    |           0x08048a05      6a25           push 0x25                   ; '%' ; '%'
    |           0x08048a07      ff75d4         push dword [local_2ch]
    |           0x08048a0a      e881fcffff     call sym.imp.fgets          ; char *fgets(char *s, int size, FILE *stream)
    |           0x08048a0f      83c410         add esp, 0x10
    |           0x08048a12      85c0           test eax, eax
    |       ,=< 0x08048a14      750a           jne 0x8048a20
    |       |   0x08048a16      b8ffffffff     mov eax, 0xffffffff         ; -1
    |      ,==< 0x08048a1b      e981010000     jmp 0x8048ba1
    |      ||      ; JMP XREF from 0x08048a14 (sym.main)
    |      |`-> 0x08048a20      83ec0c         sub esp, 0xc
    |      |    0x08048a23      6a0a           push 0xa
    |      |    0x08048a25      e846fdffff     call sym.imp.putchar        ; int putchar(int c)
    |      |    0x08048a2a      83c410         add esp, 0x10
    |      |    0x08048a2d      83ec08         sub esp, 8
    |      |    0x08048a30      6a0a           push 0xa
    |      |    0x08048a32      ff75d4         push dword [local_2ch]
    |      |    0x08048a35      e816fdffff     call sym.imp.strchr         ; char*strchr(char *s, int c)
    |      |    0x08048a3a      83c410         add esp, 0x10
    |      |    0x08048a3d      8945d8         mov dword [local_28h], eax
    |      |    0x08048a40      837dd800       cmp dword [local_28h], 0
    |      |,=< 0x08048a44      7406           je 0x8048a4c
    |      ||   0x08048a46      8b45d8         mov eax, dword [local_28h]
    |      ||   0x08048a49      c60000         mov byte [eax], 0
    |      ||      ; JMP XREF from 0x08048a44 (sym.main)
    |      |`-> 0x08048a4c      83ec0c         sub esp, 0xc
    |      |    0x08048a4f      ff75d4         push dword [local_2ch]
    |      |    0x08048a52      e852010000     call sym.check_flag_0
    |      |    0x08048a57      83c410         add esp, 0x10
    |      |    0x08048a5a      85c0           test eax, eax
    |      |,=< 0x08048a5c      741c           je 0x8048a7a
    |      ||   0x08048a5e      83ec0c         sub esp, 0xc
    |      ||   0x08048a61      68ada50408     push str.flag_0:_Confirmed_ ; 0x804a5ad ; "flag 0: Confirmed!"
    |      ||   0x08048a66      e895fcffff     call sym.imp.puts           ; int puts(const char *s)
    |      ||   0x08048a6b      83c410         add esp, 0x10
    |      ||   0x08048a6e      c745f4010000.  mov dword [local_ch], 1
    |     ,===< 0x08048a75      e9d8000000     jmp 0x8048b52
    |     |||      ; JMP XREF from 0x08048a5c (sym.main)
    |     ||`-> 0x08048a7a      83ec0c         sub esp, 0xc
    |     ||    0x08048a7d      ff75d4         push dword [local_2ch]
    |     ||    0x08048a80      e856010000     call sym.check_flag_1
    |     ||    0x08048a85      83c410         add esp, 0x10
    |     ||    0x08048a88      85c0           test eax, eax
    |     ||,=< 0x08048a8a      741c           je 0x8048aa8
    |     |||   0x08048a8c      83ec0c         sub esp, 0xc
    |     |||   0x08048a8f      68c0a50408     push str.flag_1:_Confirmed_ ; 0x804a5c0 ; "flag 1: Confirmed!"
    |     |||   0x08048a94      e867fcffff     call sym.imp.puts           ; int puts(const char *s)
    |     |||   0x08048a99      83c410         add esp, 0x10
    |     |||   0x08048a9c      c745f4010000.  mov dword [local_ch], 1
    |    ,====< 0x08048aa3      e9aa000000     jmp 0x8048b52
    |    ||||      ; JMP XREF from 0x08048a8a (sym.main)
    |    |||`-> 0x08048aa8      83ec0c         sub esp, 0xc
    |    |||    0x08048aab      ff75d4         push dword [local_2ch]
    |    |||    0x08048aae      e83a030000     call sym.check_flag_2
    |    |||    0x08048ab3      83c410         add esp, 0x10
    |    |||    0x08048ab6      85c0           test eax, eax
    |    |||,=< 0x08048ab8      7419           je 0x8048ad3
    |    ||||   0x08048aba      83ec0c         sub esp, 0xc
    |    ||||   0x08048abd      68d3a50408     push str.flag_2:_Confirmed_ ; 0x804a5d3 ; "flag 2: Confirmed!"
    |    ||||   0x08048ac2      e839fcffff     call sym.imp.puts           ; int puts(const char *s)
    |    ||||   0x08048ac7      83c410         add esp, 0x10
    |    ||||   0x08048aca      c745f4010000.  mov dword [local_ch], 1
    |   ,=====< 0x08048ad1      eb7f           jmp 0x8048b52
    |   |||||      ; JMP XREF from 0x08048ab8 (sym.main)
    |   ||||`-> 0x08048ad3      83ec0c         sub esp, 0xc
    |   ||||    0x08048ad6      ff75d4         push dword [local_2ch]
    |   ||||    0x08048ad9      e85d050000     call sym.check_flag_3
    |   ||||    0x08048ade      83c410         add esp, 0x10
    |   ||||    0x08048ae1      85c0           test eax, eax
    |   ||||,=< 0x08048ae3      7419           je 0x8048afe
    |   |||||   0x08048ae5      83ec0c         sub esp, 0xc
    |   |||||   0x08048ae8      68e6a50408     push str.flag_3:_Confirmed_ ; 0x804a5e6 ; "flag 3: Confirmed!"
    |   |||||   0x08048aed      e80efcffff     call sym.imp.puts           ; int puts(const char *s)
    |   |||||   0x08048af2      83c410         add esp, 0x10
    |   |||||   0x08048af5      c745f4010000.  mov dword [local_ch], 1
    |  ,======< 0x08048afc      eb54           jmp 0x8048b52
    |  ||||||      ; JMP XREF from 0x08048ae3 (sym.main)
    |  |||||`-> 0x08048afe      83ec0c         sub esp, 0xc
    |  |||||    0x08048b01      ff75d4         push dword [local_2ch]
    |  |||||    0x08048b04      e8d5060000     call sym.check_flag_4
    |  |||||    0x08048b09      83c410         add esp, 0x10
    |  |||||    0x08048b0c      85c0           test eax, eax
    |  |||||,=< 0x08048b0e      7419           je 0x8048b29
    |  ||||||   0x08048b10      83ec0c         sub esp, 0xc
    |  ||||||   0x08048b13      68f9a50408     push str.flag_4:_Confirmed_ ; 0x804a5f9 ; "flag 4: Confirmed!"
    |  ||||||   0x08048b18      e8e3fbffff     call sym.imp.puts           ; int puts(const char *s)
    |  ||||||   0x08048b1d      83c410         add esp, 0x10
    |  ||||||   0x08048b20      c745f4010000.  mov dword [local_ch], 1
    | ,=======< 0x08048b27      eb29           jmp 0x8048b52
    | |||||||      ; JMP XREF from 0x08048b0e (sym.main)
    | ||||||`-> 0x08048b29      83ec0c         sub esp, 0xc
    | ||||||    0x08048b2c      ff75d4         push dword [local_2ch]
    | ||||||    0x08048b2f      e8680a0000     call sym.check_flag_5
    | ||||||    0x08048b34      83c410         add esp, 0x10
    | ||||||    0x08048b37      85c0           test eax, eax
    | ||||||,=< 0x08048b39      7417           je 0x8048b52
    | |||||||   0x08048b3b      83ec0c         sub esp, 0xc
    | |||||||   0x08048b3e      680ca60408     push str.flag_5:_Confirmed_ ; 0x804a60c ; "flag 5: Confirmed!"
    | |||||||   0x08048b43      e8b8fbffff     call sym.imp.puts           ; int puts(const char *s)
    | |||||||   0x08048b48      83c410         add esp, 0x10
    | |||||||   0x08048b4b      c745f4010000.  mov dword [local_ch], 1
    | |||||||      ; XREFS: JMP 0x08048b27  JMP 0x08048afc  JMP 0x08048ad1  
    | |||||||      ; XREFS: JMP 0x08048aa3  JMP 0x08048a75  JMP 0x08048b39  
    | `````-`-> 0x08048b52      837df400       cmp dword [local_ch], 0
    |      |,=< 0x08048b56      7423           je 0x8048b7b
    |      ||   0x08048b58      83ec08         sub esp, 8
    |      ||   0x08048b5b      ff75e4         push dword [local_1ch]
    |      ||   0x08048b5e      68a1a50408     push str._n_s_n             ; 0x804a5a1 ; "\n%s\n"
    |      ||   0x08048b63      e808fbffff     call sym.imp.printf         ; int printf(const char *format)
    |      ||   0x08048b68      83c410         add esp, 0x10
    |      ||   0x08048b6b      83ec0c         sub esp, 0xc
    |      ||   0x08048b6e      ff75dc         push dword [local_24h]
    |      ||   0x08048b71      e88afbffff     call sym.imp.puts           ; int puts(const char *s)
    |      ||   0x08048b76      83c410         add esp, 0x10
    |     ,===< 0x08048b79      eb21           jmp 0x8048b9c
    |     |||      ; JMP XREF from 0x08048b56 (sym.main)
    |     ||`-> 0x08048b7b      83ec08         sub esp, 8
    |     ||    0x08048b7e      ff75e8         push dword [local_18h]
    |     ||    0x08048b81      68a1a50408     push str._n_s_n             ; 0x804a5a1 ; "\n%s\n"
    |     ||    0x08048b86      e8e5faffff     call sym.imp.printf         ; int printf(const char *format)
    |     ||    0x08048b8b      83c410         add esp, 0x10
    |     ||    0x08048b8e      83ec0c         sub esp, 0xc
    |     ||    0x08048b91      ff75e0         push dword [local_20h]
    |     ||    0x08048b94      e867fbffff     call sym.imp.puts           ; int puts(const char *s)
    |     ||    0x08048b99      83c410         add esp, 0x10
    |     ||       ; JMP XREF from 0x08048b79 (sym.main)
    |     `---> 0x08048b9c      b800000000     mov eax, 0
    |      |       ; JMP XREF from 0x08048a1b (sym.main)
    |      `--> 0x08048ba1      8b4dfc         mov ecx, dword [local_4h_2]
    |           0x08048ba4      c9             leave
    |           0x08048ba5      8d61fc         lea esp, [ecx - 4]
    \           0x08048ba8      c3             ret
    

in main it puts some strings in locals, which is fine, whatever... and then calls getuid(), followed by testing if the returned uid is 0 (eg, root). So if this program is not run as root, it'll write one 0x3d byte string to stderr, the Unclean mortal! thing we saw before.

I dunno about you, but I don't want to run this as root. I don't know GDB too well, and didn't want to figure out how to script it, so the easier option is to patch1 the binary. So I replaced the 0x74 at file offset 0x96b with 0xeb, which changes je 0x804898e into jmp 0x804898e.

With that out of the way, and the patch applied, we can run the program, enter the flag from before, and see it is, in fact, a flag.

+50.

(yes, you can easily see the string in the diassembly too)

.. and remember to actually submit the flag, or someone else on your team might do it first! I say, speaking from personal experience..

Flag 1

No more flags in the strings output, it's about time to start looking a little more in-depth at this thing.

Going back to main, we can see the gist of this program is:

  1. getuid() to check for root
  2. printf() some lovecrafty text
  3. fgets() to read a string
  4. print a "\n" after user input
  5. strchr() the input for '\n' (no idea why!)
  6. if (check_flag_0(input)) { puts("confirmed"); return }
  7. if (check_flag_1(input)) { puts("confirmed"); return }
  8. if (check_flag_2(input)) { puts("confirmed"); return }
  9. if (check_flag_3(input)) { puts("confirmed"); return }
  10. if (check_flag_4(input)) { puts("confirmed"); return }
  11. if (check_flag_5(input)) { puts("confirmed"); return }

which means we can look at each flag check independently, and hopefully none of the check_flag_N functions interact with each other or some global state. By luck and the benevolence of emptymonkey, they happen to not, and we can in fact look at the flag checking functions independently.

pdf @ sym.check_flag_1 (most of it, anyway):

/ (fcn) sym.check_flag_1 530
    |   sym.check_flag_1 (int arg_8h, );
    |           ; var int local_4h @ ebp-0x4
    |           ; arg int arg_8h @ ebp+0x8
    |           ; var int local_28h @ ebp-0x28
    |           ; var int local_24h @ ebp-0x24
    |           ; var int local_20h @ ebp-0x20
    |           ; var int local_1ch @ ebp-0x1c
    |           ; var int local_18h @ ebp-0x18
    |           ; var int local_14h @ ebp-0x14
    |           ; var int local_10h @ ebp-0x10
    |           ; var int local_ch @ ebp-0xc
    |           ; var int local_4dh @ ebp-0x4d
    |           ; var int local_4eh @ ebp-0x4e
    |           ; var int local_4fh @ ebp-0x4f
    |           ; var int local_50h @ ebp-0x50
    |           ; var int local_51h @ ebp-0x51
    |           ; var int local_52h @ ebp-0x52
    |           ; var int local_53h @ ebp-0x53
    |           ; var int local_54h @ ebp-0x54
    |           ; var int local_55h @ ebp-0x55
    |           ; var int local_56h @ ebp-0x56
    |           ; var int local_57h @ ebp-0x57
    |           ; var int local_58h @ ebp-0x58
    |           ; var int local_59h @ ebp-0x59
    |           ; var int local_5ah @ ebp-0x5a
    |           ; var int local_5bh @ ebp-0x5b
    |           ; var int local_5ch @ ebp-0x5c
    |           ; var int local_5dh @ ebp-0x5d
    |           ; var int local_5eh @ ebp-0x5e
    |           ; var int local_5fh @ ebp-0x5f
    |           ; var int local_60h @ ebp-0x60
    |           ; var int local_61h @ ebp-0x61
    |           ; var int local_62h @ ebp-0x62
    |           ; var int local_63h @ ebp-0x63
    |           ; var int local_64h @ ebp-0x64
    |           ; var int local_65h @ ebp-0x65
    |           ; var int local_66h @ ebp-0x66
    |           ; var int local_67h @ ebp-0x67
    |           ; var int local_68h @ ebp-0x68
    |           ; var int local_69h @ ebp-0x69
    |           ; var int local_6ah @ ebp-0x6a
    |           ; var int local_6bh @ ebp-0x6b
    |           ; var int local_6ch @ ebp-0x6c
    |           ; var int local_6dh @ ebp-0x6d
    |           ; var int local_6eh @ ebp-0x6e
    |           ; var int local_6fh @ ebp-0x6f
    |           ; var int local_70h @ ebp-0x70
    |           ; var int local_29h @ ebp-0x29
    |           ; var int local_2ah @ ebp-0x2a
    |           ; var int local_2bh @ ebp-0x2b
    |           ; var int local_2ch @ ebp-0x2c
    |           ; var int local_2dh @ ebp-0x2d
    |           ; var int local_2eh @ ebp-0x2e
    |           ; var int local_2fh @ ebp-0x2f
    |           ; var int local_30h @ ebp-0x30
    |           ; var int local_31h @ ebp-0x31
    |           ; var int local_32h @ ebp-0x32
    |           ; var int local_33h @ ebp-0x33
    |           ; var int local_34h @ ebp-0x34
    |           ; var int local_35h @ ebp-0x35
    |           ; var int local_36h @ ebp-0x36
    |           ; var int local_37h @ ebp-0x37
    |           ; var int local_38h @ ebp-0x38
    |           ; var int local_39h @ ebp-0x39
    |           ; var int local_3ah @ ebp-0x3a
    |           ; var int local_3bh @ ebp-0x3b
    |           ; var int local_3ch @ ebp-0x3c
    |           ; var int local_3dh @ ebp-0x3d
    |           ; var int local_3eh @ ebp-0x3e
    |           ; var int local_3fh @ ebp-0x3f
    |           ; var int local_40h @ ebp-0x40
    |           ; var int local_41h @ ebp-0x41
    |           ; var int local_42h @ ebp-0x42
    |           ; var int local_43h @ ebp-0x43
    |           ; var int local_44h @ ebp-0x44
    |           ; var int local_45h @ ebp-0x45
    |           ; var int local_46h @ ebp-0x46
    |           ; var int local_47h @ ebp-0x47
    |           ; var int local_48h @ ebp-0x48
    |           ; var int local_49h @ ebp-0x49
    |           ; var int local_4ah @ ebp-0x4a
    |           ; var int local_4bh @ ebp-0x4b
    |           ; var int local_4ch @ ebp-0x4c
    |              ; CALL XREF from 0x08048a80 (sym.main)
    |           0x08048bdb      55             push ebp                    ; .//flag_0.c:14
    |           0x08048bdc      89e5           mov ebp, esp
    |           0x08048bde      53             push ebx
    |           0x08048bdf      83ec74         sub esp, 0x74               ; 't'
    |           0x08048be2      c645b4e4       mov byte [local_4ch], 0xe4  ; .//flag_1.c:9
    |           0x08048be6      c645b543       mov byte [local_4bh], 0x43  ; 'C'
    |           0x08048bea      c645b651       mov byte [local_4ah], 0x51  ; 'Q'
    |           0x08048bee      c645b750       mov byte [local_49h], 0x50  ; 'P'
    |           0x08048bf2      c645b8c2       mov byte [local_48h], 0xc2
    |           0x08048bf6      c645b918       mov byte [local_47h], 0x18
    |           0x08048bfa      c645bae4       mov byte [local_46h], 0xe4
    |           0x08048bfe      c645bb25       mov byte [local_45h], 0x25  ; '%'
    |           0x08048c02      c645bc83       mov byte [local_44h], 0x83
    |           0x08048c06      c645bdc7       mov byte [local_43h], 0xc7
    |           0x08048c0a      c645bee2       mov byte [local_42h], 0xe2
    |           0x08048c0e      c645bf3c       mov byte [local_41h], 0x3c  ; '<'
    |           0x08048c12      c645c0fd       mov byte [local_40h], 0xfd
    |           0x08048c16      c645c1db       mov byte [local_3fh], 0xdb
    |           0x08048c1a      c645c21b       mov byte [local_3eh], 0x1b
    |           0x08048c1e      c645c323       mov byte [local_3dh], 0x23  ; '#'
    |           0x08048c22      c645c490       mov byte [local_3ch], 0x90
    |           0x08048c26      c645c518       mov byte [local_3bh], 0x18
    |           0x08048c2a      c645c6ce       mov byte [local_3ah], 0xce
    |           0x08048c2e      c645c71c       mov byte [local_39h], 0x1c
    |           0x08048c32      c645c81f       mov byte [local_38h], 0x1f
    |           0x08048c36      c645c9de       mov byte [local_37h], 0xde
    |           0x08048c3a      c645caf2       mov byte [local_36h], 0xf2
    |           0x08048c3e      c645cb20       mov byte [local_35h], 0x20
    |           0x08048c42      c645cc36       mov byte [local_34h], 0x36  ; '6'
    |           0x08048c46      c645cd5e       mov byte [local_33h], 0x5e  ; '^'
    |           0x08048c4a      c645ce1d       mov byte [local_32h], 0x1d
    |           0x08048c4e      c645cf63       mov byte [local_31h], 0x63  ; 'c'
    |           0x08048c52      c645d095       mov byte [local_30h], 0x95
    |           0x08048c56      c645d127       mov byte [local_2fh], 0x27  ; '''
    |           0x08048c5a      c645d216       mov byte [local_2eh], 0x16
    |           0x08048c5e      c645d310       mov byte [local_2dh], 0x10
    |           0x08048c62      c645d4d8       mov byte [local_2ch], 0xd8
    |           0x08048c66      c645d5b5       mov byte [local_2bh], 0xb5
    |           0x08048c6a      c645d6de       mov byte [local_2ah], 0xde
    |           0x08048c6e      c645d713       mov byte [local_29h], 0x13
    |           0x08048c72      c6459081       mov byte [local_70h], 0x81  ; .//flag_1.c:10
    |           0x08048c76      c6459173       mov byte [local_6fh], 0x73  ; 's'
    |           0x08048c7a      c6459230       mov byte [local_6eh], 0x30  ; '0'
    |           0x08048c7e      c6459367       mov byte [local_6dh], 0x67  ; 'g'
    |           0x08048c82      c64594f5       mov byte [local_6ch], 0xf5
    |           0x08048c86      c645957c       mov byte [local_6bh], 0x7c  ; '|'
    |           0x08048c8a      c6459685       mov byte [local_6ah], 0x85
    |           0x08048c8e      c6459746       mov byte [local_69h], 0x46  ; 'F'
    |           0x08048c92      c64598ae       mov byte [local_68h], 0xae
    |           0x08048c96      c64599f4       mov byte [local_67h], 0xf4
    |           0x08048c9a      c6459ada       mov byte [local_66h], 0xda
    |           0x08048c9e      c6459b0f       mov byte [local_65h], 0xf
    |           0x08048ca2      c6459ccc       mov byte [local_64h], 0xcc
    |           0x08048ca6      c6459df6       mov byte [local_63h], 0xf6
    |           0x08048caa      c6459e2a       mov byte [local_62h], 0x2a  ; '*'
    |           0x08048cae      c6459f12       mov byte [local_61h], 0x12
    |           0x08048cb2      c645a0f5       mov byte [local_60h], 0xf5
    |           0x08048cb6      c645a12f       mov byte [local_5fh], 0x2f  ; '/'
    |           0x08048cba      c645a2e3       mov byte [local_5eh], 0xe3
    |           0x08048cbe      c645a37d       mov byte [local_5dh], 0x7d  ; '}'
    |           0x08048cc2      c645a47d       mov byte [local_5ch], 0x7d  ; '}'
    |           0x08048cc6      c645a5ec       mov byte [local_5bh], 0xec
    |           0x08048cca      c645a6ca       mov byte [local_5ah], 0xca
    |           0x08048cce      c645a70d       mov byte [local_59h], 0xd
    |           0x08048cd2      c645a855       mov byte [local_58h], 0x55  ; 'U'
    |           0x08048cd6      c645a938       mov byte [local_57h], 0x38  ; '8'
    |           0x08048cda      c645aa28       mov byte [local_56h], 0x28  ; '('
    |           0x08048cde      c645ab50       mov byte [local_55h], 0x50  ; 'P'
    |           0x08048ce2      c645aca6       mov byte [local_54h], 0xa6
    |           0x08048ce6      c645ad15       mov byte [local_53h], 0x15
    |           0x08048cea      c645ae70       mov byte [local_52h], 0x70  ; 'p'
    |           0x08048cee      c645af76       mov byte [local_51h], 0x76  ; 'v'
    |           0x08048cf2      c645b0bd       mov byte [local_50h], 0xbd
    |           0x08048cf6      c645b1d1       mov byte [local_4fh], 0xd1
    |           0x08048cfa      c645b2eb       mov byte [local_4eh], 0xeb
    |           0x08048cfe      c645b371       mov byte [local_4dh], 0x71  ; 'q'
    |           0x08048d02      c745f4000000.  mov dword [local_ch], 0     ; .//flag_1.c:12
    |           0x08048d09      83ec08         sub esp, 8                  ; .//flag_1.c:16
    |           0x08048d0c      6a18           push 0x18                   ; " \x88\x04\b4"
    |           0x08048d0e      6a01           push 1
    |           0x08048d10      e8fbfaffff     call sym.imp.calloc         ; void *calloc(size_t nmeb, size_t size)
    |           0x08048d15      83c410         add esp, 0x10
    |           0x08048d18      8945f0         mov dword [local_10h], eax
    |           0x08048d1b      837df000       cmp dword [local_10h], 0
    |       ,=< 0x08048d1f      752b           jne 0x8048d4c
    |       |   0x08048d21      e85afaffff     call sym.imp.__errno_location ; .//flag_1.c:17
    |       |   0x08048d26      8b00           mov eax, dword [eax]
    |       |   0x08048d28      c745ecffffff.  mov dword [local_14h], 0xffffffff
    |       |   0x08048d2f      8945e8         mov dword [local_18h], eax
    |       |   0x08048d32      c745e445a604.  mov dword [local_1ch], 0x804a645
    |       |   0x08048d39      6a18           push 0x18                   ; /usr/include/i386-linux-gnu/bits/error.h:42 ; " \x88\x04\b4"
    |       |   0x08048d3b      ff75e4         push dword [local_1ch]
    |       |   0x08048d3e      ff75e8         push dword [local_18h]
    |       |   0x08048d41      ff75ec         push dword [local_14h]
    |       |   0x08048d44      e8a7f9ffff     call sym.imp.error
    |       |   0x08048d49      83c410         add esp, 0x10
    |       |      ; JMP XREF from 0x08048d1f (sym.check_flag_1)
    |       `-> 0x08048d4c      8b45f0         mov eax, dword [local_10h]  ; .//flag_1.c:20
    |           0x08048d4f      c70024000000   mov dword [eax], 0x24       ; '$' ; [0x24:4]=0 ; '$'
    |           0x08048d55      8b45f0         mov eax, dword [local_10h]  ; .//flag_1.c:21
    |           0x08048d58      8d55b4         lea edx, [local_4ch]
    |           0x08048d5b      895008         mov dword [eax + 8], edx
    |           0x08048d5e      8b45f0         mov eax, dword [local_10h]  ; .//flag_1.c:22
    |           0x08048d61      8d5590         lea edx, [local_70h]
    |           0x08048d64      89500c         mov dword [eax + 0xc], edx
    |           0x08048d67      83ec0c         sub esp, 0xc                ; .//flag_1.c:24
    |           0x08048d6a      ff75f0         push dword [local_10h]
    |           0x08048d6d      e86e0e0000     call sym.xorscura_decrypt
    |           0x08048d72      83c410         add esp, 0x10
    |           0x08048d75      83f8ff         cmp eax, 0xffffffffffffffff
    |       ,=< 0x08048d78      752d           jne 0x8048da7
    |       |   0x08048d7a      8b5df0         mov ebx, dword [local_10h]  ; .//flag_1.c:25
    |       |   0x08048d7d      e8fef9ffff     call sym.imp.__errno_location
    |       |   0x08048d82      8b00           mov eax, dword [eax]
    |       |   0x08048d84      c745e0ffffff.  mov dword [local_20h], 0xffffffff
    |       |   0x08048d8b      8945dc         mov dword [local_24h], eax
    |       |   0x08048d8e      c745d853a604.  mov dword [local_28h], 0x804a653
    |       |   0x08048d95      53             push ebx                    ; /usr/include/i386-linux-gnu/bits/error.h:42
    |       |   0x08048d96      ff75d8         push dword [local_28h]
    |       |   0x08048d99      ff75dc         push dword [local_24h]
    |       |   0x08048d9c      ff75e0         push dword [local_20h]
    |       |   0x08048d9f      e84cf9ffff     call sym.imp.error
    |       |   0x08048da4      83c410         add esp, 0x10
    |       |      ; JMP XREF from 0x08048d78 (sym.check_flag_1)
    |       `-> 0x08048da7      8b45f0         mov eax, dword [local_10h]  ; .//flag_1.c:28
    |           0x08048daa      8b4004         mov eax, dword [eax + 4]    ; [0x4:4]=0x10101
    |           0x08048dad      83ec04         sub esp, 4
    |           0x08048db0      6a24           push 0x24                   ; '$' ; '$'
    |           0x08048db2      ff7508         push dword [arg_8h]
    |           0x08048db5      50             push eax
    |           0x08048db6      e805faffff     call sym.imp.strncmp        ; int strncmp(const char *s1, const char *s2, size_t n)
    |           0x08048dbb      83c410         add esp, 0x10
    |           0x08048dbe      85c0           test eax, eax
    |       ,=< 0x08048dc0      7507           jne 0x8048dc9
    |       |   0x08048dc2      c745f4010000.  mov dword [local_ch], 1     ; .//flag_1.c:29
    |       |      ; JMP XREF from 0x08048dc0 (sym.check_flag_1)
    |       `-> 0x08048dc9      83ec0c         sub esp, 0xc                ; .//flag_1.c:32
    |           0x08048dcc      ff75f0         push dword [local_10h]
    |           0x08048dcf      e87c100000     call sym.xorscura_free_xod  ; void free(void *ptr)
    |           0x08048dd4      83c410         add esp, 0x10
    |           0x08048dd7      83ec0c         sub esp, 0xc                ; .//flag_1.c:33
    |           0x08048dda      ff75f0         push dword [local_10h]
    |           0x08048ddd      e89ef8ffff     call sym.imp.free           ; void free(void *ptr)
    |           0x08048de2      83c410         add esp, 0x10
    |           0x08048de5      8b45f4         mov eax, dword [local_ch]   ; .//flag_1.c:35
    |           0x08048de8      8b5dfc         mov ebx, dword [local_4h]   ; .//flag_1.c:36
    |           0x08048deb      c9             leave
    \           0x08048dec      c3             ret
    

Immediately we can see that a bunch of data is being mov'd onto the stack, followed by a calloc(), a call to some xorscura_decrypt() function, and a strncmp(). Interestingly, the stack data is written one byte at a time, suggesting the compiler didn't want to optimize too hard - going four bytes at a time would save ~81 bytes.

In the interest of lazy, it's probably safe to assume that the decoded flag is being strncmp()'d with the user input, so it's time to learn how to use GDB a little!

gdb Sheb-Teth.bin is good to get started, then set a breakpoint at the strncmp() call of interest with b *0x8048db6. The * notation is GDB for specifying an address (rather than a symbol).

Now, r to run the program, enter some string as input, c to continue on and hope all goes as planned with us eventually hitting that breakpoint.

We do hit it, and at this point the program is paused immediately before calling strncmp(), with the stack set up just as it needs to be. x/3x $esp shows the three 32-bit integers from where esp points, going upwards with each successive one, which corresponds to strncmp() arguments in left to right order

Flags are 36-character UUIDs, so 0x24 makes sense. x/s 0x804c008 shows our initial input, so x/s 0x804c868 should show us a flag - which it pleasantly does.

+100.

Flag 2

pdf @ sym.check_flag_2

/ (fcn) sym.check_flag_2 570
    |   sym.check_flag_2 (int arg_8h, );
    |           ; var int local_4h @ ebp-0x4
    |           ; arg int arg_8h @ ebp+0x8
    |           ; var int local_34h @ ebp-0x34
    |           ; var int local_30h @ ebp-0x30
    |           ; var int local_2ch @ ebp-0x2c
    |           ; var int local_28h @ ebp-0x28
    |           ; var int local_24h @ ebp-0x24
    |           ; var int local_20h @ ebp-0x20
    |           ; var int local_1ch @ ebp-0x1c
    |           ; var int local_59h @ ebp-0x59
    |           ; var int local_10h @ ebp-0x10
    |           ; var int local_18h @ ebp-0x18
    |           ; var int local_ch @ ebp-0xc
    |           ; var int local_35h @ ebp-0x35
    |           ; var int local_36h @ ebp-0x36
    |           ; var int local_37h @ ebp-0x37
    |           ; var int local_38h @ ebp-0x38
    |           ; var int local_39h @ ebp-0x39
    |           ; var int local_3ah @ ebp-0x3a
    |           ; var int local_3bh @ ebp-0x3b
    |           ; var int local_3ch @ ebp-0x3c
    |           ; var int local_3dh @ ebp-0x3d
    |           ; var int local_3eh @ ebp-0x3e
    |           ; var int local_3fh @ ebp-0x3f
    |           ; var int local_40h @ ebp-0x40
    |           ; var int local_41h @ ebp-0x41
    |           ; var int local_42h @ ebp-0x42
    |           ; var int local_43h @ ebp-0x43
    |           ; var int local_44h @ ebp-0x44
    |           ; var int local_45h @ ebp-0x45
    |           ; var int local_46h @ ebp-0x46
    |           ; var int local_47h @ ebp-0x47
    |           ; var int local_48h @ ebp-0x48
    |           ; var int local_49h @ ebp-0x49
    |           ; var int local_4ah @ ebp-0x4a
    |           ; var int local_4bh @ ebp-0x4b
    |           ; var int local_4ch @ ebp-0x4c
    |           ; var int local_4dh @ ebp-0x4d
    |           ; var int local_4eh @ ebp-0x4e
    |           ; var int local_4fh @ ebp-0x4f
    |           ; var int local_50h @ ebp-0x50
    |           ; var int local_51h @ ebp-0x51
    |           ; var int local_52h @ ebp-0x52
    |           ; var int local_53h @ ebp-0x53
    |           ; var int local_54h @ ebp-0x54
    |           ; var int local_55h @ ebp-0x55
    |           ; var int local_56h @ ebp-0x56
    |           ; var int local_57h @ ebp-0x57
    |           ; var int local_58h @ ebp-0x58
    |           ; var int local_14h @ ebp-0x14
    |              ; CALL XREF from 0x08048aae (sym.main)
    |           0x08048ded      55             push ebp                    ; .//flag_1.c:36
    |           0x08048dee      89e5           mov ebp, esp
    |           0x08048df0      53             push ebx
    |           0x08048df1      83ec64         sub esp, 0x64               ; 'd'
    |           0x08048df4      c745ecea2a38.  mov dword [local_14h], 0xcc382aea ; .//flag_2.c:11
    |           0x08048dfb      c645a895       mov byte [local_58h], 0x95  ; .//flag_2.c:12
    |           0x08048dff      c645a9c5       mov byte [local_57h], 0xc5
    |           0x08048e03      c645aab5       mov byte [local_56h], 0xb5
    |           0x08048e07      c645ab15       mov byte [local_55h], 0x15
    |           0x08048e0b      c645acbb       mov byte [local_54h], 0xbb
    |           0x08048e0f      c645add8       mov byte [local_53h], 0xd8
    |           0x08048e13      c645ae4b       mov byte [local_52h], 0x4b  ; 'K'
    |           0x08048e17      c645af55       mov byte [local_51h], 0x55  ; 'U'
    |           0x08048e1b      c645b035       mov byte [local_50h], 0x35  ; '5'
    |           0x08048e1f      c645b103       mov byte [local_4fh], 3
    |           0x08048e23      c645b22b       mov byte [local_4eh], 0x2b  ; '+'
    |           0x08048e27      c645b340       mov byte [local_4dh], 0x40  ; '@'
    |           0x08048e2b      c645b429       mov byte [local_4ch], 0x29  ; ')'
    |           0x08048e2f      c645b5c3       mov byte [local_4bh], 0xc3
    |           0x08048e33      c645b6de       mov byte [local_4ah], 0xde
    |           0x08048e37      c645b711       mov byte [local_49h], 0x11
    |           0x08048e3b      c645b891       mov byte [local_48h], 0x91
    |           0x08048e3f      c645b978       mov byte [local_47h], 0x78  ; 'x'
    |           0x08048e43      c645bab0       mov byte [local_46h], 0xb0
    |           0x08048e47      c645bb5c       mov byte [local_45h], 0x5c  ; '\'
    |           0x08048e4b      c645bce2       mov byte [local_44h], 0xe2
    |           0x08048e4f      c645bdee       mov byte [local_43h], 0xee
    |           0x08048e53      c645beb8       mov byte [local_42h], 0xb8
    |           0x08048e57      c645bf7f       mov byte [local_41h], 0x7f
    |           0x08048e5b      c645c0cd       mov byte [local_40h], 0xcd
    |           0x08048e5f      c645c1a5       mov byte [local_3fh], 0xa5
    |           0x08048e63      c645c20b       mov byte [local_3eh], 0xb
    |           0x08048e67      c645c366       mov byte [local_3dh], 0x66  ; 'f'
    |           0x08048e6b      c645c4d7       mov byte [local_3ch], 0xd7
    |           0x08048e6f      c645c5a3       mov byte [local_3bh], 0xa3
    |           0x08048e73      c645c673       mov byte [local_3ah], 0x73  ; 's'
    |           0x08048e77      c645c748       mov byte [local_39h], 0x48  ; 'H'
    |           0x08048e7b      c645c8d7       mov byte [local_38h], 0xd7
    |           0x08048e7f      c645c9d7       mov byte [local_37h], 0xd7
    |           0x08048e83      c645ca74       mov byte [local_36h], 0x74  ; 't'
    |           0x08048e87      c645cb66       mov byte [local_35h], 0x66  ; 'f'
    |           0x08048e8b      c745f4000000.  mov dword [local_ch], 0     ; .//flag_2.c:14
    |           0x08048e92      83ec08         sub esp, 8                  ; .//flag_2.c:29
    |           0x08048e95      6a00           push 0
    |           0x08048e97      6869a60408     push str._proc_self_status  ; 0x804a669 ; "/proc/self/status"
    |           0x08048e9c      e89ff8ffff     call sym.imp.open           ; int open(const char *path, int oflag)
    |           0x08048ea1      83c410         add esp, 0x10
    |           0x08048ea4      8945e8         mov dword [local_18h], eax
    |           0x08048ea7      c745f0070000.  mov dword [local_10h], 7    ; .//flag_2.c:32
    |       ,=< 0x08048eae      eb20           jmp 0x8048ed0               ; .//flag_2.c:33
    |       |      ; JMP XREF from 0x08048ed4 (sym.check_flag_2)
    |      .--> 0x08048eb0      83ec04         sub esp, 4                  ; .//flag_2.c:34
    |      ||   0x08048eb3      6a01           push 1
    |      ||   0x08048eb5      8d45a7         lea eax, [local_59h]
    |      ||   0x08048eb8      50             push eax
    |      ||   0x08048eb9      ff75e8         push dword [local_18h]
    |      ||   0x08048ebc      e89ff7ffff     call sym.imp.read           ; ssize_t read(int fildes, void *buf, size_t nbyte)
    |      ||   0x08048ec1      83c410         add esp, 0x10
    |      ||   0x08048ec4      0fb645a7       movzx eax, byte [local_59h] ; .//flag_2.c:35
    |      ||   0x08048ec8      3c0a           cmp al, 0xa
    |     ,===< 0x08048eca      7504           jne 0x8048ed0
    |     |||   0x08048ecc      836df001       sub dword [local_10h], 1    ; .//flag_2.c:36
    |     |!|      ; JMP XREF from 0x08048eae (sym.check_flag_2)
    |     |!|      ; JMP XREF from 0x08048eca (sym.check_flag_2)
    |     `-`-> 0x08048ed0      837df000       cmp dword [local_10h], 0    ; .//flag_2.c:33
    |      `==< 0x08048ed4      75da           jne 0x8048eb0
    |           0x08048ed6      c745f0010000.  mov dword [local_10h], 1    ; .//flag_2.c:41
    |       ,=< 0x08048edd      eb20           jmp 0x8048eff               ; .//flag_2.c:42
    |       |      ; JMP XREF from 0x08048f03 (sym.check_flag_2)
    |      .--> 0x08048edf      83ec04         sub esp, 4                  ; .//flag_2.c:43
    |      ||   0x08048ee2      6a01           push 1
    |      ||   0x08048ee4      8d45a7         lea eax, [local_59h]
    |      ||   0x08048ee7      50             push eax
    |      ||   0x08048ee8      ff75e8         push dword [local_18h]
    |      ||   0x08048eeb      e870f7ffff     call sym.imp.read           ; ssize_t read(int fildes, void *buf, size_t nbyte)
    |      ||   0x08048ef0      83c410         add esp, 0x10
    |      ||   0x08048ef3      0fb645a7       movzx eax, byte [local_59h] ; .//flag_2.c:44
    |      ||   0x08048ef7      3c09           cmp al, 9
    |     ,===< 0x08048ef9      7504           jne 0x8048eff
    |     |||   0x08048efb      836df001       sub dword [local_10h], 1    ; .//flag_2.c:45
    |     |!|      ; JMP XREF from 0x08048edd (sym.check_flag_2)
    |     |!|      ; JMP XREF from 0x08048ef9 (sym.check_flag_2)
    |     `-`-> 0x08048eff      837df000       cmp dword [local_10h], 0    ; .//flag_2.c:42
    |      `==< 0x08048f03      75da           jne 0x8048edf
    |           0x08048f05      83ec04         sub esp, 4                  ; .//flag_2.c:52
    |           0x08048f08      6a01           push 1
    |           0x08048f0a      8d45a7         lea eax, [local_59h]
    |           0x08048f0d      50             push eax
    |           0x08048f0e      ff75e8         push dword [local_18h]
    |           0x08048f11      e84af7ffff     call sym.imp.read           ; ssize_t read(int fildes, void *buf, size_t nbyte)
    |           0x08048f16      83c410         add esp, 0x10
    |           0x08048f19      83ec0c         sub esp, 0xc                ; .//flag_2.c:53
    |           0x08048f1c      ff75e8         push dword [local_18h]
    |           0x08048f1f      e8ccf8ffff     call sym.imp.close          ; int close(int fildes)
    |           0x08048f24      83c410         add esp, 0x10
    |           0x08048f27      83ec0c         sub esp, 0xc                ; .//flag_2.c:56
    |           0x08048f2a      8d45a7         lea eax, [local_59h]
    |           0x08048f2d      50             push eax
    |           0x08048f2e      e86df8ffff     call sym.imp.atoi           ; int atoi(const char *str)
    |           0x08048f33      83c410         add esp, 0x10
    |           0x08048f36      85c0           test eax, eax
    |       ,=< 0x08048f38      7405           je 0x8048f3f
    |       |   0x08048f3a      e823090000     call sym.eldritch_function  ; .//flag_2.c:57
    |       |      ; JMP XREF from 0x08048f38 (sym.check_flag_2)
    |       `-> 0x08048f3f      83ec08         sub esp, 8                  ; .//flag_2.c:61
    |           0x08048f42      6a18           push 0x18                   ; " \x88\x04\b4"
    |           0x08048f44      6a01           push 1
    |           0x08048f46      e8c5f8ffff     call sym.imp.calloc         ; void *calloc(size_t nmeb, size_t size)
    |           0x08048f4b      83c410         add esp, 0x10
    |           0x08048f4e      8945e4         mov dword [local_1ch], eax
    |           0x08048f51      837de400       cmp dword [local_1ch], 0
    |       ,=< 0x08048f55      752b           jne 0x8048f82
    |       |   0x08048f57      e824f8ffff     call sym.imp.__errno_location ; .//flag_2.c:62
    |       |   0x08048f5c      8b00           mov eax, dword [eax]
    |       |   0x08048f5e      c745e0ffffff.  mov dword [local_20h], 0xffffffff
    |       |   0x08048f65      8945dc         mov dword [local_24h], eax
    |       |   0x08048f68      c745d87ba604.  mov dword [local_28h], 0x804a67b
    |       |   0x08048f6f      6a18           push 0x18                   ; /usr/include/i386-linux-gnu/bits/error.h:42 ; " \x88\x04\b4"
    |       |   0x08048f71      ff75d8         push dword [local_28h]
    |       |   0x08048f74      ff75dc         push dword [local_24h]
    |       |   0x08048f77      ff75e0         push dword [local_20h]
    |       |   0x08048f7a      e871f7ffff     call sym.imp.error
    |       |   0x08048f7f      83c410         add esp, 0x10
    |       |      ; JMP XREF from 0x08048f55 (sym.check_flag_2)
    |       `-> 0x08048f82      8b45e4         mov eax, dword [local_1ch]  ; .//flag_2.c:65
    |           0x08048f85      c70024000000   mov dword [eax], 0x24       ; '$' ; [0x24:4]=0 ; '$'
    |           0x08048f8b      8b45e4         mov eax, dword [local_1ch]  ; .//flag_2.c:66
    |           0x08048f8e      8b55ec         mov edx, dword [local_14h]
    |           0x08048f91      895010         mov dword [eax + 0x10], edx
    |           0x08048f94      8b45e4         mov eax, dword [local_1ch]  ; .//flag_2.c:67
    |           0x08048f97      8d55a8         lea edx, [local_58h]
    |           0x08048f9a      89500c         mov dword [eax + 0xc], edx
    |           0x08048f9d      83ec0c         sub esp, 0xc                ; .//flag_2.c:71
    |           0x08048fa0      ff75e4         push dword [local_1ch]
    |           0x08048fa3      e8380c0000     call sym.xorscura_decrypt
    |           0x08048fa8      83c410         add esp, 0x10
    |           0x08048fab      83f8ff         cmp eax, 0xffffffffffffffff
    |       ,=< 0x08048fae      752d           jne 0x8048fdd
    |       |   0x08048fb0      8b5de4         mov ebx, dword [local_1ch]  ; .//flag_2.c:72
    |       |   0x08048fb3      e8c8f7ffff     call sym.imp.__errno_location
    |       |   0x08048fb8      8b00           mov eax, dword [eax]
    |       |   0x08048fba      c745d4ffffff.  mov dword [local_2ch], 0xffffffff
    |       |   0x08048fc1      8945d0         mov dword [local_30h], eax
    |       |   0x08048fc4      c745cc89a604.  mov dword [local_34h], 0x804a689
    |       |   0x08048fcb      53             push ebx                    ; /usr/include/i386-linux-gnu/bits/error.h:42
    |       |   0x08048fcc      ff75cc         push dword [local_34h]
    |       |   0x08048fcf      ff75d0         push dword [local_30h]
    |       |   0x08048fd2      ff75d4         push dword [local_2ch]
    |       |   0x08048fd5      e816f7ffff     call sym.imp.error
    |       |   0x08048fda      83c410         add esp, 0x10
    |       |      ; JMP XREF from 0x08048fae (sym.check_flag_2)
    |       `-> 0x08048fdd      8b45e4         mov eax, dword [local_1ch]  ; .//flag_2.c:75
    |           0x08048fe0      8b10           mov edx, dword [eax]
    |           0x08048fe2      8b45e4         mov eax, dword [local_1ch]
    |           0x08048fe5      8b4004         mov eax, dword [eax + 4]    ; [0x4:4]=0x10101
    |           0x08048fe8      83ec04         sub esp, 4
    |           0x08048feb      52             push edx
    |           0x08048fec      50             push eax
    |           0x08048fed      ff7508         push dword [arg_8h]
    |           0x08048ff0      e8cbf7ffff     call sym.imp.strncmp        ; int strncmp(const char *s1, const char *s2, size_t n)
    |           0x08048ff5      83c410         add esp, 0x10
    |           0x08048ff8      85c0           test eax, eax
    |       ,=< 0x08048ffa      7507           jne 0x8049003
    |       |   0x08048ffc      c745f4010000.  mov dword [local_ch], 1     ; .//flag_2.c:76
    |       |      ; JMP XREF from 0x08048ffa (sym.check_flag_2)
    |       `-> 0x08049003      83ec0c         sub esp, 0xc                ; .//flag_2.c:79
    |           0x08049006      ff75e4         push dword [local_1ch]
    |           0x08049009      e8420e0000     call sym.xorscura_free_xod  ; void free(void *ptr)
    |           0x0804900e      83c410         add esp, 0x10
    |           0x08049011      83ec0c         sub esp, 0xc                ; .//flag_2.c:80
    |           0x08049014      ff75e4         push dword [local_1ch]
    |           0x08049017      e864f6ffff     call sym.imp.free           ; void free(void *ptr)
    |           0x0804901c      83c410         add esp, 0x10
    |           0x0804901f      8b45f4         mov eax, dword [local_ch]   ; .//flag_2.c:82
    |           0x08049022      8b5dfc         mov ebx, dword [local_4h]   ; .//flag_2.c:83
    |           0x08049025      c9             leave
    \           0x08049026      c3             ret
    

This is where things get more fun. The rest of the challenges involve some measure of anti-debugging, and here we can see:

  1. open() /proc/self/status
  2. store that file descriptor at ebp + 0x18
  3. read() that file descriptor a bit
  4. read() a little more
  5. read() one last time into the buffer at ebp + 0x59h. Looking a little more closely shows all nbyte values for the number of bytes to read is 1 here, and before.
  6. close() the file descriptor
  7. atoi() the byte that was read into ebp + 0x59h
  8. if atoi() returned 0, skip over eldritch_function(), otherwise call it.
  9. same flag-checking mechanics from here as in check_flag_1

So, clearly, something is interesting about /proc/self/status. I'm not familiar with it, so it's time to take a look:

    Name:   vim
    State:  R (running)
    Tgid:   25100
    Ngid:   0
    Pid:    25100
    PPid:   11187
    TracerPid:  0
    Uid:    1000    1000    1000    1000
    Gid:    1000    1000    1000    1000
    [snip]

Most of these fields are clear enough, though I'm not sure about Tgid, Ngid, PPid, or TracerPid. It's probably safe to assume the gid are related to the group id of the self process, where PPid is probably the parent PID, leaving TracerPid as an unknown. I'm going to guess that if a debugger is attached to the process, TracerPid probably indicates what's tracing the process, so probably the pid of the debugger attached, with 0 for there isn't a debugger attached.

Going back to the code, the first read() use is in a loop counting down from 7, comparing each byte read to 0xa (eg, "\n"), so it's seeking down to the 8th line. That would be the Uid line, which threw me initially. This is right after the TracerPid line which is significantly more interesting here. I'm quite certain this is actually a bug on most systems but happens to work because Uid is "supposed" to be 0 (run as root). I patched the 7 in mov dword [local_10h], 7 to 6 so it looks in the right place and doesn't segfault when run as non-root outside a debugger.

Then, the second read() loop goes forward until it reads a 0x9 ("\t") (or a null, but it won't). The fields in /proc/self/status are tab-delimited, so it's scanning forward to the first number.

The third read() reads the first digit of whatever number we're at, which will be 0 if the number is 0, or any non-0 digit otherwise, beause these values are not 0-padded.

So when the program atoi()'s whatever digit we read, it'll that number as a value in eax - if the intent was to read the number on the TracerPid line, this would check for a debugger. As things stand, this is a duplicate uid check for 0.. I think.

One way or the other, this ends up calling eldritch_function which ends with a fairly nonsensical ret 0xcfd, almost guaranteeing a segfualt when it returns. Which it, in fact, does.

Again the fan of binary patching, I replaced the 0x74 at 0xf38 in the binary with 0xeb, changing the conditional jump into a constant jump, bypassing eldritch_function() no matter what.

Throw a breakpoint on the strncmp here at 0x8048ff0, run again, and x/3x $esp and follow the two pointers there for x/s 0x804c868, which prints out another flag!

+200

Flag 3

/ (fcn) sym.check_flag_3 415
    |   sym.check_flag_3 (int arg_8h, );
    |           ; var int local_4h @ ebp-0x4
    |           ; var int local_30h @ ebp-0x30
    |           ; var int local_2ch @ ebp-0x2c
    |           ; var int local_28h @ ebp-0x28
    |           ; var int local_18h @ ebp-0x18
    |           ; arg int arg_8h @ ebp+0x8
    |           ; var int local_24h @ ebp-0x24
    |           ; var int local_20h @ ebp-0x20
    |           ; var int local_1ch @ ebp-0x1c
    |           ; var int local_14h @ ebp-0x14
    |           ; var int local_ch @ ebp-0xc
    |           ; var int local_10h @ ebp-0x10
    |           ; var int local_31h @ ebp-0x31
    |           ; var int local_32h @ ebp-0x32
    |           ; var int local_33h @ ebp-0x33
    |           ; var int local_34h @ ebp-0x34
    |           ; var int local_35h @ ebp-0x35
    |           ; var int local_36h @ ebp-0x36
    |           ; var int local_37h @ ebp-0x37
    |           ; var int local_38h @ ebp-0x38
    |           ; var int local_39h @ ebp-0x39
    |           ; var int local_3ah @ ebp-0x3a
    |           ; var int local_3bh @ ebp-0x3b
    |           ; var int local_3ch @ ebp-0x3c
    |           ; var int local_3dh @ ebp-0x3d
    |           ; var int local_3eh @ ebp-0x3e
    |           ; var int local_3fh @ ebp-0x3f
    |           ; var int local_40h @ ebp-0x40
    |           ; var int local_41h @ ebp-0x41
    |           ; var int local_42h @ ebp-0x42
    |           ; var int local_43h @ ebp-0x43
    |           ; var int local_44h @ ebp-0x44
    |           ; var int local_45h @ ebp-0x45
    |           ; var int local_46h @ ebp-0x46
    |           ; var int local_47h @ ebp-0x47
    |           ; var int local_48h @ ebp-0x48
    |           ; var int local_49h @ ebp-0x49
    |           ; var int local_4ah @ ebp-0x4a
    |           ; var int local_4bh @ ebp-0x4b
    |           ; var int local_4ch @ ebp-0x4c
    |           ; var int local_4dh @ ebp-0x4d
    |           ; var int local_4eh @ ebp-0x4e
    |           ; var int local_4fh @ ebp-0x4f
    |           ; var int local_50h @ ebp-0x50
    |           ; var int local_51h @ ebp-0x51
    |           ; var int local_52h @ ebp-0x52
    |           ; var int local_53h @ ebp-0x53
    |           ; var int local_54h @ ebp-0x54
    |              ; CALL XREF from 0x08048ad9 (sym.main)
    |           0x0804903b      55             push ebp
    |           0x0804903c      89e5           mov ebp, esp
    |           0x0804903e      53             push ebx
    |           0x0804903f      83ec54         sub esp, 0x54               ; 'T'
    |           0x08049042      c645ac0e       mov byte [local_54h], 0xe
    |           0x08049046      c645ad45       mov byte [local_53h], 0x45  ; 'E'
    |           0x0804904a      c645ae9c       mov byte [local_52h], 0x9c
    |           0x0804904e      c645af33       mov byte [local_51h], 0x33  ; '3'
    |           0x08049052      c645b098       mov byte [local_50h], 0x98
    |           0x08049056      c645b1af       mov byte [local_4fh], 0xaf
    |           0x0804905a      c645b249       mov byte [local_4eh], 0x49  ; 'I'
    |           0x0804905e      c645b328       mov byte [local_4dh], 0x28  ; '('
    |           0x08049062      c645b41c       mov byte [local_4ch], 0x1c
    |           0x08049066      c645b503       mov byte [local_4bh], 3
    |           0x0804906a      c645b603       mov byte [local_4ah], 3
    |           0x0804906e      c645b762       mov byte [local_49h], 0x62  ; 'b'
    |           0x08049072      c645b8ee       mov byte [local_48h], 0xee
    |           0x08049076      c645b9b7       mov byte [local_47h], 0xb7
    |           0x0804907a      c645ba87       mov byte [local_46h], 0x87
    |           0x0804907e      c645bb20       mov byte [local_45h], 0x20
    |           0x08049082      c645bc90       mov byte [local_44h], 0x90
    |           0x08049086      c645bd41       mov byte [local_43h], 0x41  ; 'A'
    |           0x0804908a      c645be8e       mov byte [local_42h], 0x8e
    |           0x0804908e      c645bf44       mov byte [local_41h], 0x44  ; 'D'
    |           0x08049092      c645c0e1       mov byte [local_40h], 0xe1
    |           0x08049096      c645c1ed       mov byte [local_3fh], 0xed
    |           0x0804909a      c645c24e       mov byte [local_3eh], 0x4e  ; 'N'
    |           0x0804909e      c645c308       mov byte [local_3dh], 8
    |           0x080490a2      c645c448       mov byte [local_3ch], 0x48  ; 'H'
    |           0x080490a6      c645c5ed       mov byte [local_3bh], 0xed
    |           0x080490aa      c645c6e6       mov byte [local_3ah], 0xe6
    |           0x080490ae      c645c71a       mov byte [local_39h], 0x1a
    |           0x080490b2      c645c828       mov byte [local_38h], 0x28  ; '('
    |           0x080490b6      c645c948       mov byte [local_37h], 0x48  ; 'H'
    |           0x080490ba      c645cab6       mov byte [local_36h], 0xb6
    |           0x080490be      c645cb37       mov byte [local_35h], 0x37  ; '7'
    |           0x080490c2      c645ccac       mov byte [local_34h], 0xac
    |           0x080490c6      c645cd33       mov byte [local_33h], 0x33  ; '3'
    |           0x080490ca      c645ce95       mov byte [local_32h], 0x95
    |           0x080490ce      c645cf07       mov byte [local_31h], 7
    |           0x080490d2      c745f0000000.  mov dword [local_10h], 0
    |           0x080490d9      c745f4000000.  mov dword [local_ch], 0
    |       ,=< 0x080490e0      eb17           jmp 0x80490f9
    |       |      ; JMP XREF from 0x080490fd (sym.check_flag_3)
    |      .--> 0x080490e2      83ec08         sub esp, 8
    |      ||   0x080490e5      6827900408     push sym.trap               ; 0x8049027 ; "U\x89\xe5\xa1\xb4\xb1\x04\b\x05\x17O\x9d\x16\xa3\xb4\xb1\x04\b]\xc3U\x89\xe5S\x83\xecT\xc6E\xac\x0e\xc6E\xadE\xc6E\xae\x9c\xc6E\xaf3\xc6E\xb0\x98\xc6E\xb1\xaf\xc6E\xb2I\xc6E\xb3(\xc6E\xb4\x1c\xc6E\xb5\x03\xc6E\xb6\x03\xc6E\xb7b\xc6E\xb8\xee\xc6E\xb9\xb7\xc6E\xba\x87\xc6E\xbb \xc6E\xbc\x90\xc6E\xbdA\xc6E\xbe\x8e\xc6E\xbfD\xc6E\xc0\xe1\xc6E\xc1\xed\xc6E\xc2N\xc6E\xc3\b\xc6E\xc4H\xc6E\xc5\xed\xc6E\xc6\xe6\xc6E\xc7\x1a\xc6E\xc8(\xc6E\xc9H\xc6E\xca\xb6\xc6E\xcb7\xc6E\xcc\xac\xc6E\xcd3\xc6E\xce\x95\xc6E\xcf\x07\xc7E\xf0"
    |      ||   0x080490ea      6a05           push 5
    |      ||   0x080490ec      e81ff6ffff     call sym.imp.__sysv_signal  ; void signal(int sig, void *func)
    |      ||   0x080490f1      83c410         add esp, 0x10
    |      ||   0x080490f4      cc             int3
           ||   0x080490f5      8345f401       add dword [ebp - 0xc], 1
    |      !|      ; JMP XREF from 0x080490e0 (sym.check_flag_3)
    |      |`-> 0x080490f9      837df405       cmp dword [local_ch], 5     ; [0x5:4]=257
    |      `==< 0x080490fd      7ee3           jle 0x80490e2
    |           0x080490ff      83ec08         sub esp, 8
    |           0x08049102      6a18           push 0x18                   ; " \x88\x04\b4"
    |           0x08049104      6a01           push 1
    |           0x08049106      e805f7ffff     call sym.imp.calloc         ; void *calloc(size_t nmeb, size_t size)
    |           0x0804910b      83c410         add esp, 0x10
    |           0x0804910e      8945ec         mov dword [local_14h], eax
    |           0x08049111      837dec00       cmp dword [local_14h], 0
    |       ,=< 0x08049115      752b           jne 0x8049142
    |       |   0x08049117      e864f6ffff     call sym.imp.__errno_location
    |       |   0x0804911c      8b00           mov eax, dword [eax]
    |       |   0x0804911e      c745e4ffffff.  mov dword [local_1ch], 0xffffffff
    |       |   0x08049125      8945e0         mov dword [local_20h], eax
    |       |   0x08049128      c745dc9fa604.  mov dword [local_24h], 0x804a69f
    |       |   0x0804912f      6a18           push 0x18                   ; " \x88\x04\b4"
    |       |   0x08049131      ff75dc         push dword [local_24h]
    |       |   0x08049134      ff75e0         push dword [local_20h]
    |       |   0x08049137      ff75e4         push dword [local_1ch]
    |       |   0x0804913a      e8b1f5ffff     call sym.imp.error
    |       |   0x0804913f      83c410         add esp, 0x10
    |       |      ; JMP XREF from 0x08049115 (sym.check_flag_3)
    |       `-> 0x08049142      8b45ec         mov eax, dword [local_14h]
    |           0x08049145      c70024000000   mov dword [eax], 0x24       ; '$' ; [0x24:4]=0 ; '$'
    |           0x0804914b      8b15b4b10408   mov edx, dword obj.elder_sign ; [0x804b1b4:4]=0x392e3420 ; " 4.9.2-10) 4.9.2"
    |           0x08049151      8b45ec         mov eax, dword [local_14h]
    |           0x08049154      895010         mov dword [eax + 0x10], edx
    |           0x08049157      8b45ec         mov eax, dword [local_14h]
    |           0x0804915a      8d55ac         lea edx, [local_54h]
    |           0x0804915d      89500c         mov dword [eax + 0xc], edx
    |           0x08049160      8b45ec         mov eax, dword [local_14h]
    |           0x08049163      8b5508         mov edx, dword [arg_8h]     ; [0x8:4]=0
    |           0x08049166      895004         mov dword [eax + 4], edx
    |           0x08049169      83ec0c         sub esp, 0xc
    |           0x0804916c      ff75ec         push dword [local_14h]
    |           0x0804916f      e84c0c0000     call sym.xorscura_compare
    |           0x08049174      83c410         add esp, 0x10
    |           0x08049177      8945e8         mov dword [local_18h], eax
    |           0x0804917a      837de8ff       cmp dword [local_18h], 0xffffffffffffffff
    |       ,=< 0x0804917e      752d           jne 0x80491ad
    |       |   0x08049180      8b5dec         mov ebx, dword [local_14h]
    |       |   0x08049183      e8f8f5ffff     call sym.imp.__errno_location
    |       |   0x08049188      8b00           mov eax, dword [eax]
    |       |   0x0804918a      c745d8ffffff.  mov dword [local_28h], 0xffffffff
    |       |   0x08049191      8945d4         mov dword [local_2ch], eax
    |       |   0x08049194      c745d0ada604.  mov dword [local_30h], 0x804a6ad
    |       |   0x0804919b      53             push ebx
    |       |   0x0804919c      ff75d0         push dword [local_30h]
    |       |   0x0804919f      ff75d4         push dword [local_2ch]
    |       |   0x080491a2      ff75d8         push dword [local_28h]
    |       |   0x080491a5      e846f5ffff     call sym.imp.error
    |       |   0x080491aa      83c410         add esp, 0x10
    |       |      ; JMP XREF from 0x0804917e (sym.check_flag_3)
    |       `-> 0x080491ad      837de800       cmp dword [local_18h], 0
    |       ,=< 0x080491b1      7507           jne 0x80491ba
    |       |   0x080491b3      c745f0010000.  mov dword [local_10h], 1
    |       |      ; JMP XREF from 0x080491b1 (sym.check_flag_3)
    |       `-> 0x080491ba      83ec0c         sub esp, 0xc
    |           0x080491bd      ff75ec         push dword [local_14h]
    |           0x080491c0      e88b0c0000     call sym.xorscura_free_xod  ; void free(void *ptr)
    |           0x080491c5      83c410         add esp, 0x10
    |           0x080491c8      83ec0c         sub esp, 0xc
    |           0x080491cb      ff75ec         push dword [local_14h]
    |           0x080491ce      e8adf4ffff     call sym.imp.free           ; void free(void *ptr)
    |           0x080491d3      83c410         add esp, 0x10
    |           0x080491d6      8b45f0         mov eax, dword [local_10h]
    |           0x080491d9      8b5dfc         mov ebx, dword [local_4h]
    |           0x080491dc      c9             leave
    \           0x080491dd      c3             ret
    

This uses signal(), which I'm not very familiar with either. A quick jaunt over to man 2 signal suggests that signal() will be called with a signal number, and a handler - some a function pointer. This makes some sense given radare is telling us that the arguments to signal() would be 5 and sym.trap, an address of the function in this binary named trap.

Additional interesting bits are the facts that signal() is called in a loop, and that signal() is immediately followed by an int3, which signals a breakpoint for an attached debugger.

So, what's special about 5? /usr/include/asm-generic/signal.h defines signal numbers for us, showing 5 is the number for SIGTRAP. man 7 signal further informs us that SIGTRAP is a signal for Trace/breakpoint trap.

At this point the trick gets clearer: signal() is being used to set a handler on SIGTRAP, but if a debugger is attached it will get the breakpoint signal first, and probably not duplicate that along to the debugged process out of the box, so the handler (trap()) will never get called. Looks like we'll have to see what trap() itself does.

/ (fcn) sym.trap 20
    |   sym.trap ();
    |              ; DATA XREF from 0x080490e5 (sym.check_flag_3)
    |           0x08049027      55             push ebp                    ; .//flag_2.c:83
    |           0x08049028      89e5           mov ebp, esp
    |           0x0804902a      a1b4b10408     mov eax, dword obj.elder_sign ; [0x804b1b4:4]=0x392e3420 ; " 4.9.2-10) 4.9.2"
    |           0x0804902f      05174f9d16     add eax, 0x169d4f17
    |           0x08049034      a3b4b10408     mov dword obj.elder_sign, eax ; [0x804b1b4:4]=0x392e3420 ; " 4.9.2-10) 4.9.2"
    |           0x08049039      5d             pop ebp
    \           0x0804903a      c3             ret
    

trap() does nothing but load a global variable, elder_sign, add to it, and store it back!

Skipping forward in check_flag_3 a little, we can see elder_sign is used before calling xorscura_compare(), so trap being called the correct number of times for it all to line up is probably important.

I'd look into trying to send SIGTRAP to the debugee and scripting that in gdb, but it seems simpler to patch the binary again to behave in a nicer way. Instead of calling trap() in a roundabout way through signal handlers, let's patch the loop body to just.. call trap(). So that's exactly what I did! At 0x10e2 in the binary, I nop'd out until 0x10f5 with 0x90 to clear some space. I stopped writing out nops there because we'd overwrite the add dword [ebp - 0xc], 1 that eventually trips the loop exit condition, which we want to preserve. Afterward, I wrote in call sym.trap at 0x10e2. Beause call is an instruction with a four byte offset, we need to figure out the relative distance to trap() from 0x80490ea. This comes out to 0xffffff38, for the whole instruction being e838ffffff. Writing that into the binary at 0x10ea should preserve the "call trap() once each loop" behavior, but not break under debugging.

xorscura_compare()

With that rudeness out of the way, we can move on with debugging this program, which gets into xorscura_compare(), a function we hadn't seen until now.

/ (fcn) sym.xorscura_compare 454
    |   sym.xorscura_compare (int arg_148h);
    |       !   ; var int local_ch @ esp+0xc
    |       !   ; var int local_14h @ esp+0x14
    |       !   ; var int local_18h @ esp+0x18
    |       !   ; var int local_1ch @ esp+0x1c
    |       !   ; var int local_1dh @ esp+0x1d
    |       !   ; var int local_1eh @ esp+0x1e
    |       !   ; var int local_1fh @ esp+0x1f
    |       !   ; var int local_20h @ esp+0x20
    |       !   ; var int local_24h @ esp+0x24
    |       !   ; arg int arg_148h @ esp+0x148
    |       !      ; CALL XREF from 0x0804916f (sym.check_flag_3)
    |       !      ; CALL XREF from 0x08049528 (sym.check_flag_4)
    |       !      ; CALL XREF from 0x080497ee (sym.check_flag_5)
    |       |   0x08049dc0      55             push ebp
    |       |   0x08049dc1      57             push edi
    |       |   0x08049dc2      56             push esi
    |       |   0x08049dc3      53             push ebx
    |       |   0x08049dc4      8b442414       mov eax, dword [local_14h]  ; [0x14:4]=1
    |       |   0x08049dc8      8b5010         mov edx, dword [eax + 0x10] ; [0x10:4]=0x30002
    |       |   0x08049dcb      85d2           test edx, edx
    |      ,==< 0x08049dcd      7411           je 0x8049de0
    |      ||   0x08049dcf      89442414       mov dword [local_14h], eax
    |      ||   0x08049dd3      5b             pop ebx
    |      ||   0x08049dd4      5e             pop esi
    |      ||   0x08049dd5      5f             pop edi
    |      ||   0x08049dd6      5d             pop ebp
    |      |`=< 0x08049dd7      e984feffff     jmp sym.xorscura_compare_prng
           |    0x08049ddc      8d742600       lea esi, [esi]
    |      |       ; JMP XREF from 0x08049dcd (sym.xorscura_compare)
    |      `--> 0x08049de0      8b5808         mov ebx, dword [eax + 8]    ; [0x8:4]=0
    |           0x08049de3      85db           test ebx, ebx
    |       ,=< 0x08049de5      7453           je 0x8049e3a
    |       |   0x08049de7      8b08           mov ecx, dword [eax]
    |       |   0x08049de9      85c9           test ecx, ecx
    |      ,==< 0x08049deb      7e3c           jle 0x8049e29
    |      ||   0x08049ded      8b700c         mov esi, dword [eax + 0xc]  ; [0xc:4]=0
    |      ||   0x08049df0      8b7804         mov edi, dword [eax + 4]    ; [0x4:4]=0x10101
    |      ||   0x08049df3      0fb603         movzx eax, byte [ebx]
    |      ||   0x08049df6      3206           xor al, byte [esi]
    |      ||   0x08049df8      0fb617         movzx edx, byte [edi]
    |      ||   0x08049dfb      0fbec0         movsx eax, al
    |      ||   0x08049dfe      39c2           cmp edx, eax
    |     ,===< 0x08049e00      752e           jne 0x8049e30
    |     |||   0x08049e02      31c0           xor eax, eax
    |    ,====< 0x08049e04      eb1c           jmp 0x8049e22
         ||||   0x08049e06      8d7600         lea esi, [esi]
         ||||   0x08049e09      8dbc27000000.  lea edi, [edi]
    |    ||||      ; JMP XREF from 0x08049e27 (sym.xorscura_compare)
    |   .-----> 0x08049e10      0fb61403       movzx edx, byte [ebx + eax]
    |   |||||   0x08049e14      0fb62c07       movzx ebp, byte [edi + eax]
    |   |||||   0x08049e18      321406         xor dl, byte [esi + eax]
    |   |||||   0x08049e1b      0fbed2         movsx edx, dl
    |   |||||   0x08049e1e      39d5           cmp ebp, edx
    |  ,======< 0x08049e20      750e           jne 0x8049e30
    |  |!||||      ; JMP XREF from 0x08049e04 (sym.xorscura_compare)
    |  ||`----> 0x08049e22      83c001         add eax, 1
    |  || |||   0x08049e25      39c8           cmp eax, ecx
    |  |`=====< 0x08049e27      75e7           jne 0x8049e10
    |  |  |||      ; JMP XREF from 0x08049deb (sym.xorscura_compare)
    |  |  |`--> 0x08049e29      31c0           xor eax, eax
    |  |  | |      ; JMP XREF from 0x08049e3f (sym.xorscura_compare)
    |  |  |.--> 0x08049e2b      5b             pop ebx
    |  |  |||   0x08049e2c      5e             pop esi
    |  |  |||   0x08049e2d      5f             pop edi
    |  |  |||   0x08049e2e      5d             pop ebp
    |  |  |||   0x08049e2f      c3             ret
    |  |  |!|      ; JMP XREF from 0x08049e00 (sym.xorscura_compare)
    |  |  |!|      ; JMP XREF from 0x08049e20 (sym.xorscura_compare)
    |  `--`---> 0x08049e30      5b             pop ebx
    |      ||   0x08049e31      b801000000     mov eax, 1
    |      ||   0x08049e36      5e             pop esi
    |      ||   0x08049e37      5f             pop edi
    |      ||   0x08049e38      5d             pop ebp
    |      ||   0x08049e39      c3             ret
    |      !|      ; JMP XREF from 0x08049de5 (sym.xorscura_compare)
    |      |`-> 0x08049e3a      b8ffffffff     mov eax, 0xffffffff         ; -1
    \      `==< 0x08049e3f      ebea           jmp 0x8049e2b
    

It looks like there are two main branches to this function, one of which is taken if a value in the struct passed in local_14h is null, the other taken if it's set. If it's set, xorscura_compare_prng is called, so I imagine that'll come into play for a later flag, with this value used in relation to the prng.

In the other case, which is what we see here, some xor'ing and cmp'ing is done. It's probably safe to say the flag is decoded and compared to user iput, so by putting a breakpoint on each cmp after a xor, we should be able to see flag bytes in registers.

There's an added complication, in that it bails out on the first mismatch. So let's patch a that out... the jne 0x8049e30 at 0x8049e00 has got to go. That bails if the first bytes don't match. At 0x1e00, I replaced that with 6690, a two-byte nop. Now we have to give the same treatment to the jne 0x8049e30 at 0x8049e20.

At this point, breakpoint'ing at 0x8049dfe and 0x8049e1e are sufficient to get us flag bytes, but we've accidentally made this function always return "true". That means flag 4 and flag 5 will be hard to get to. So let's fix that up by transmuting xor eax, eax at 0x80489e29 into inc eax; inc eax. That way it only returns 0 if eax happened to be -2, which is... exceedingly unlikely. That one just replacing the 31c0 at 0x1e29 in the binary with 4040.

And it is at exactly this point we may realize that for flag 3, we actually follow the branch to xorscura_compare_prng(). Don't worry, the above patching comes in handy for later flags.

xorscura_compare_prng()

/ (fcn) sym.xorscura_compare_prng 308
    |   sym.xorscura_compare_prng ();
    |           ; var int local_ch @ esp+0xc
    |           ; var int local_18h @ esp+0x18
    |           ; var int local_1ch @ esp+0x1c
    |           ; var int local_1dh @ esp+0x1d
    |           ; var int local_1eh @ esp+0x1e
    |           ; var int local_1fh @ esp+0x1f
    |           ; var int local_20h @ esp+0x20
    |           ; var int local_24h @ esp+0x24
    |           ; var int local_148h @ esp+0x148
    |              ; JMP XREF from 0x08049dd7 (sym.xorscura_compare)
    |           0x08049c60      55             push ebp
    |           0x08049c61      57             push edi
    |           0x08049c62      56             push esi
    |           0x08049c63      53             push ebx
    |           0x08049c64      81ec34010000   sub esp, 0x134
    |           0x08049c6a      8bb424480100.  mov esi, dword [local_148h] ; [0x148:4]=4
    |           0x08049c71      6a1c           push 0x1c                   ; "4"
    |           0x08049c73      6a01           push 1
    |           0x08049c75      e896ebffff     call sym.imp.calloc         ; void *calloc(size_t nmeb, size_t size)
    |           0x08049c7a      8944241c       mov dword [local_1ch], eax
    |           0x08049c7e      83c410         add esp, 0x10
    |           0x08049c81      85c0           test eax, eax
    |       ,=< 0x08049c83      0f8427010000   je 0x8049db0
    |       |   0x08049c89      8d542420       lea edx, [local_20h]        ; 0x20
    |       |   0x08049c8d      31c0           xor eax, eax
    |       |   0x08049c8f      b940000000     mov ecx, 0x40               ; '@' ; "4\x80\x04\b"
    |       |   0x08049c94      89d7           mov edi, edx
    |       |   0x08049c96      f3ab           rep stosd dword es:[edi], eax
    |       |   0x08049c98      ff74240c       push dword [local_ch]
    |       |   0x08049c9c      6800010000     push 0x100
    |       |   0x08049ca1      52             push edx
    |       |   0x08049ca2      ff7610         push dword [esi + 0x10]
    |       |   0x08049ca5      e856ebffff     call sym.imp.initstate_r
    |       |   0x08049caa      83c410         add esp, 0x10
    |       |   0x08049cad      83f8ff         cmp eax, 0xffffffffffffffff
    |      ,==< 0x08049cb0      0f84fa000000   je 0x8049db0
    |      ||   0x08049cb6      8b2e           mov ebp, dword [esi]
    |      ||   0x08049cb8      31db           xor ebx, ebx
    |      ||      ; JMP XREF from 0x08049da2 (sym.xorscura_compare_prng)
    |     .---> 0x08049cba      39d3           cmp ebx, edx
    |    ,====< 0x08049cbc      0f839f000000   jae 0x8049d61
    |    |!||      ; JMP XREF from 0x08049d5b (sym.xorscura_compare_prng)
    |   .-----> 0x08049cc2      83ec08         sub esp, 8
    |   |||||   0x08049cc5      8d442424       lea eax, [local_24h]        ; 0x24 ; '$'
    |   |||||   0x08049cc9      50             push eax
    |   |||||   0x08049cca      ff742418       push dword [local_18h]
    |   |||||   0x08049cce      e8ddeaffff     call sym.imp.random_r       ; int rand(void)
    |   |||||   0x08049cd3      83c410         add esp, 0x10
    |   |||||   0x08049cd6      83f8ff         cmp eax, 0xffffffffffffffff
    |  ,======< 0x08049cd9      0f84d1000000   je 0x8049db0
    |  ||||||   0x08049cdf      8b4e0c         mov ecx, dword [esi + 0xc]  ; [0xc:4]=0
    |  ||||||   0x08049ce2      8b7e0c         mov edi, dword [esi + 0xc]  ; [0xc:4]=0
    |  ||||||   0x08049ce5      0fb6041f       movzx eax, byte [edi + ebx]
    |  ||||||   0x08049ce9      3244241c       xor al, byte [local_1ch]
    |  ||||||   0x08049ced      666690         nop
    |  ||||||   0x08049cf0      50             push eax
    |  ||||||   0x08049cf1      54             push esp
    |  ||||||   0x08049cf2      e809eaffff     call sym.imp.puts           ; int puts(const char *s)
    |  ||||||   0x08049cf7      58             pop eax
    |  ||||||   0x08049cf8      58             pop eax
    |  ||||||   0x08049cf9      666690         nop
    |  ||||||   0x08049cfc      8b16           mov edx, dword [esi]
    |  ||||||   0x08049cfe      8d4301         lea eax, [ebx + 1]
    |  ||||||   0x08049d01      39c2           cmp edx, eax
    | ,=======< 0x08049d03      0f8497000000   je 0x8049da0
    | |||||||   0x08049d09      0fb6441f01     movzx eax, byte [edi + ebx + 1] ; [0x1:1]=69
    | |||||||   0x08049d0e      3244241d       xor al, byte [local_1dh]
    | |||||||   0x08049d12      666690         nop
    | |||||||   0x08049d15      50             push eax
    | |||||||   0x08049d16      54             push esp
    | |||||||   0x08049d17      e8e4e9ffff     call sym.imp.puts           ; int puts(const char *s)
    | |||||||   0x08049d1c      58             pop eax
    | |||||||   0x08049d1d      58             pop eax
    | |||||||   0x08049d1e      8d4302         lea eax, [ebx + 2]
    | |||||||   0x08049d21      39c2           cmp edx, eax
    | ========< 0x08049d23      747b           je 0x8049da0
    | |||||||   0x08049d25      0fb6441f02     movzx eax, byte [edi + ebx + 2] ; [0x2:1]=76
    | |||||||   0x08049d2a      3244241e       xor al, byte [local_1eh]
    | |||||||   0x08049d2e      666690         nop
    | |||||||   0x08049d31      50             push eax
    | |||||||   0x08049d32      54             push esp
    | |||||||   0x08049d33      e8c8e9ffff     call sym.imp.puts           ; int puts(const char *s)
    | |||||||   0x08049d38      58             pop eax
    | |||||||   0x08049d39      58             pop eax
    | |||||||   0x08049d3a      8d4303         lea eax, [ebx + 3]          ; "F\x01\x01\x01"
    | |||||||   0x08049d3d      39c2           cmp edx, eax
    | ========< 0x08049d3f      745f           je 0x8049da0
    | |||||||   0x08049d41      0fb6441f03     movzx eax, byte [edi + ebx + 3] ; [0x3:1]=70 ; "F\x01\x01\x01"
    | |||||||   0x08049d46      3244241f       xor al, byte [local_1fh]
    | |||||||   0x08049d4a      666690         nop
    | |||||||   0x08049d4d      50             push eax
    | |||||||   0x08049d4e      54             push esp
    | |||||||   0x08049d4f      e8ace9ffff     call sym.imp.puts           ; int puts(const char *s)
    | |||||||   0x08049d54      58             pop eax
    | |||||||   0x08049d55      58             pop eax
    | |||||||   0x08049d56      83c304         add ebx, 4
    | |||||||   0x08049d59      39eb           cmp ebx, ebp
    | ||`=====< 0x08049d5b      0f8261ffffff   jb 0x8049cc2
    | || |!||      ; JMP XREF from 0x08049cbc (sym.xorscura_compare_prng)
    | || `----> 0x08049d61      83ec0c         sub esp, 0xc
    | ||  |||   0x08049d64      ff742418       push dword [local_18h]
    | ||  |||   0x08049d68      e813e9ffff     call sym.imp.free           ; void free(void *ptr)
    | ||  |||   0x08049d6d      83c410         add esp, 0x10
    | ||  |||   0x08049d70      31c0           xor eax, eax
    | ||  |||   0x08049d72      81c42c010000   add esp, 0x12c
    | ||  |||   0x08049d78      5b             pop ebx
    | ||  |||   0x08049d79      5e             pop esi
    | ||  |||   0x08049d7a      5f             pop edi
    | ||  |||   0x08049d7b      5d             pop ebp
    | ||  |||   0x08049d7c      c3             ret
      ||  |||   0x08049d7d      8d7600         lea esi, [esi]
      ||  |||   0x08049d80      83ec0c         sub esp, 0xc
      ||  |||   0x08049d83      ff742418       push dword [esp + 0x18]
      ||  |||   0x08049d87      e8f4e8ffff     call sym.imp.free           ; void free(void *ptr)
      ||  |||   0x08049d8c      83c410         add esp, 0x10
      ||  |||   0x08049d8f      b801000000     mov eax, 1
      ||  |||   0x08049d94      81c42c010000   add esp, 0x12c
      ||  |||   0x08049d9a      5b             pop ebx
      ||  |||   0x08049d9b      5e             pop esi
      ||  |||   0x08049d9c      5f             pop edi
      ||  |||   0x08049d9d      5d             pop ebp
      ||  |||   0x08049d9e      c3             ret
      ||  |||   0x08049d9f      90             nop
    | ||  !||      ; JMP XREF from 0x08049d03 (sym.xorscura_compare_prng)
    | ||  !||      ; JMP XREF from 0x08049d23 (sym.xorscura_compare_prng)
    | ||  !||      ; JMP XREF from 0x08049d3f (sym.xorscura_compare_prng)
    | `-------> 0x08049da0      89d3           mov ebx, edx
    |  |  `===< 0x08049da2      e913ffffff     jmp 0x8049cba
       |   ||   0x08049da7      89f6           mov esi, esi
       |   ||   0x08049da9      8dbc27000000.  lea edi, [edi]
    |  |   ||      ; JMP XREF from 0x08049c83 (sym.xorscura_compare_prng)
    |  |   ||      ; JMP XREF from 0x08049cb0 (sym.xorscura_compare_prng)
    |  |   ||      ; JMP XREF from 0x08049cd9 (sym.xorscura_compare_prng)
    |  `---``-> 0x08049db0      81c42c010000   add esp, 0x12c
    |           0x08049db6      b8ffffffff     mov eax, 0xffffffff         ; -1
    |           0x08049dbb      5b             pop ebx
    |           0x08049dbc      5e             pop esi
    |           0x08049dbd      5f             pop edi
    |           0x08049dbe      5d             pop ebp
    \           0x08049dbf      c3             ret
    
  1. calloc() 0x1c bytes
  2. initstate_r with that struct
  3. do some stuff and maybe random_r with that struct
  4. after random_r, bytes are decoded one at a time, in groups of four, each compared to a corresponding byte of user input
  5. if any decoded byte does not match up, return 1.

Much like in xorscura_compare(), this will exit early if any bytes of the flag don't match, but it'd be nice for it to just print out all bytes of the flag.

nop'ing out conditional jumps at 0x8049cf6, 0x8049d1c, 0x8049d38, and 0x8049d54 should do the trick, though we'll need to "fix" xor eax, eax at 0x8049d70 just as before, where inc eax; inc eax will do.

       ,==< 0x08049cd9      0f84d1000000   je 0x8049db0
           ||   0x08049cdf      8b4e0c         mov ecx, dword [esi + 0xc]  ; [0xc:4]=0
           ||   0x08049ce2      8b7e04         mov edi, dword [esi + 4]    ; [0x4:4]=0x10101
           ||   0x08049ce5      0fb60419       movzx eax, byte [ecx + ebx]
           ||   0x08049ce9      0fb6141f       movzx edx, byte [edi + ebx]
           ||   0x08049ced      3244241c       xor al, byte [esp + 0x1c]
           ||   0x08049cf1      0fbec0         movsx eax, al
           ||   0x08049cf4      39c2           cmp edx, eax
           ||   0x08049cf6      666666666690   nop
           ||   0x08049cfc      8b16           mov edx, dword [esi]
           ||   0x08049cfe      8d4301         lea eax, [ebx + 1]
           ||   0x08049d01      39c2           cmp edx, eax
          ,===< 0x08049d03      0f8497000000   je 0x8049da0
          |||   0x08049d09      0fb6441901     movzx eax, byte [ecx + ebx + 1] ; [0x1:1]=69
          |||   0x08049d0e      0fb66c1f01     movzx ebp, byte [edi + ebx + 1] ; [0x1:1]=69
          |||   0x08049d13      3244241d       xor al, byte [esp + 0x1d]
          |||   0x08049d17      0fbec0         movsx eax, al
          |||   0x08049d1a      39c5           cmp ebp, eax
          |||   0x08049d1c      6690           nop
          |||   0x08049d1e      8d4302         lea eax, [ebx + 2]
          |||   0x08049d21      39c2           cmp edx, eax
         ,====< 0x08049d23      747b           je 0x8049da0
         ||||   0x08049d25      0fb6441902     movzx eax, byte [ecx + ebx + 2] ; [0x2:1]=76
         ||||   0x08049d2a      0fb66c1f02     movzx ebp, byte [edi + ebx + 2] ; [0x2:1]=76
         ||||   0x08049d2f      3244241e       xor al, byte [esp + 0x1e]
         ||||   0x08049d33      0fbec0         movsx eax, al
         ||||   0x08049d36      39c5           cmp ebp, eax
        ,=====< 0x08049d38      7546           jne 0x8049d80
        |||||   0x08049d3a      8d4303         lea eax, [ebx + 3]          ; "F\x01\x01\x01"
        |||||   0x08049d3d      39c2           cmp edx, eax
       ,======< 0x08049d3f      745f           je 0x8049da0
       ||||||   0x08049d41      0fb6441903     movzx eax, byte [ecx + ebx + 3] ; [0x3:1]=70 ; "F\x01\x01\x01"
       ||||||   0x08049d46      0fb67c1f03     movzx edi, byte [edi + ebx + 3] ; [0x3:1]=70 ; "F\x01\x01\x01"
       ||||||   0x08049d4b      3244241f       xor al, byte [esp + 0x1f]
       ||||||   0x08049d4f      0fbec0         movsx eax, al
       ||||||   0x08049d52      39c7           cmp edi, eax
      ,=======< 0x08049d54      752a           jne 0x8049d80
      |||||||   0x08049d56      83c304         add ebx, 4
      |||||||   0x08049d59      39d3           cmp ebx, edx
      ||||||`=< 0x08049d5b      0f8261ffffff   jb 0x8049cc2
      ||||||    0x08049d61      83ec0c         sub esp, 0xc
      ||||||    0x08049d64      ff742418       push dword [esp + 0x18]
      ||||||    0x08049d68      e813e9ffff     call sym.imp.free
      ||||||    0x08049d6d      83c410         add esp, 0x10
      ||||||    0x08049d70      31c0           xor eax, eax
      ||||||    0x08049d72      81c42c010000   add esp, 0x12c
      ||||||    0x08049d78      5b             pop ebx
      ||||||    0x08049d79      5e             pop esi
      ||||||    0x08049d7a      5f             pop edi
      ||||||    0x08049d7b      5d             pop ebp
      ||||||    0x08049d7c      c3             ret
    

Now with breakpoints at 0x8049cf4, 0x8049d1a, 0x8049d36, and 0x8049d52 and display/c $eax we'll get a flag one byte at a time when run and debugged!

+300

Flag 4

/ (fcn) sym.check_flag_4 751
    |   sym.check_flag_4 ();
    |           ; var int local_8h @ ebp-0x8
    |           ; var int local_58h @ ebp-0x58
    |           ; var int local_54h @ ebp-0x54
    |           ; var int local_50h @ ebp-0x50
    |           ; var int local_30h @ ebp-0x30
    |           ; var int local_2ch @ ebp-0x2c
    |           ; var int local_40h @ ebp-0x40
    |           ; var int local_3ch @ ebp-0x3c
    |           ; var int local_38h @ ebp-0x38
    |           ; var int local_28h @ ebp-0x28
    |           ; var int local_1ch @ ebp-0x1c
    |           ; var int local_24h @ ebp-0x24
    |           ; var int local_9dh @ ebp-0x9d
    |           ; var int local_9eh @ ebp-0x9e
    |           ; var int local_9fh @ ebp-0x9f
    |           ; var int local_a0h @ ebp-0xa0
    |           ; var int local_a1h @ ebp-0xa1
    |           ; var int local_a2h @ ebp-0xa2
    |           ; var int local_a3h @ ebp-0xa3
    |           ; var int local_a4h @ ebp-0xa4
    |           ; var int local_a5h @ ebp-0xa5
    |           ; var int local_a6h @ ebp-0xa6
    |           ; var int local_a7h @ ebp-0xa7
    |           ; var int local_a8h @ ebp-0xa8
    |           ; var int local_a9h @ ebp-0xa9
    |           ; var int local_aah @ ebp-0xaa
    |           ; var int local_20h @ ebp-0x20
    |           ; var int local_79h @ ebp-0x79
    |           ; var int local_7ah @ ebp-0x7a
    |           ; var int local_7bh @ ebp-0x7b
    |           ; var int local_7ch @ ebp-0x7c
    |           ; var int local_7dh @ ebp-0x7d
    |           ; var int local_7eh @ ebp-0x7e
    |           ; var int local_7fh @ ebp-0x7f
    |           ; var int local_80h @ ebp-0x80
    |           ; var int local_81h @ ebp-0x81
    |           ; var int local_82h @ ebp-0x82
    |           ; var int local_83h @ ebp-0x83
    |           ; var int local_84h @ ebp-0x84
    |           ; var int local_85h @ ebp-0x85
    |           ; var int local_86h @ ebp-0x86
    |           ; var int local_87h @ ebp-0x87
    |           ; var int local_88h @ ebp-0x88
    |           ; var int local_89h @ ebp-0x89
    |           ; var int local_8ah @ ebp-0x8a
    |           ; var int local_8bh @ ebp-0x8b
    |           ; var int local_8ch @ ebp-0x8c
    |           ; var int local_8dh @ ebp-0x8d
    |           ; var int local_8eh @ ebp-0x8e
    |           ; var int local_8fh @ ebp-0x8f
    |           ; var int local_90h @ ebp-0x90
    |           ; var int local_91h @ ebp-0x91
    |           ; var int local_92h @ ebp-0x92
    |           ; var int local_93h @ ebp-0x93
    |           ; var int local_94h @ ebp-0x94
    |           ; var int local_95h @ ebp-0x95
    |           ; var int local_96h @ ebp-0x96
    |           ; var int local_97h @ ebp-0x97
    |           ; var int local_98h @ ebp-0x98
    |           ; var int local_99h @ ebp-0x99
    |           ; var int local_9ah @ ebp-0x9a
    |           ; var int local_9bh @ ebp-0x9b
    |           ; var int local_9ch @ ebp-0x9c
    |           ; var int local_78h @ ebp-0x78
    |           ; var int local_4h @ esp+0x4
    |              ; CALL XREF from 0x08048b04 (sym.main)
    |           0x080491de      8d4c2404       lea ecx, [local_4h]
    |           0x080491e2      83e4e0         and esp, 0xffffffe0
    |           0x080491e5      ff71fc         push dword [ecx - 4]
    |           0x080491e8      55             push ebp
    |           0x080491e9      89e5           mov ebp, esp
    |           0x080491eb      53             push ebx
    |           0x080491ec      51             push ecx
    |           0x080491ed      81ecb0000000   sub esp, 0xb0
    |           0x080491f3      89cb           mov ebx, ecx
    |           0x080491f5      c74588ed0508.  mov dword [local_78h], 0x570805ed
    |           0x080491fc      c68564ffffff.  mov byte [local_9ch], 0xd3
    |           0x08049203      c68565ffffff.  mov byte [local_9bh], 0x67  ; 'g'
    |           0x0804920a      c68566ffffff.  mov byte [local_9ah], 0x3d  ; '='
    |           0x08049211      c68567ffffff.  mov byte [local_99h], 0x33  ; '3'
    |           0x08049218      c68568ffffff.  mov byte [local_98h], 0x2c  ; ','
    |           0x0804921f      c68569ffffff.  mov byte [local_97h], 0x48  ; 'H'
    |           0x08049226      c6856affffff.  mov byte [local_96h], 0x39  ; '9'
    |           0x0804922d      c6856bffffff.  mov byte [local_95h], 0x20
    |           0x08049234      c6856cffffff.  mov byte [local_94h], 0xad
    |           0x0804923b      c6856dffffff.  mov byte [local_93h], 0xcf
    |           0x08049242      c6856effffff.  mov byte [local_92h], 0xd
    |           0x08049249      c6856fffffff.  mov byte [local_91h], 0xb
    |           0x08049250      c68570ffffff.  mov byte [local_90h], 0xab
    |           0x08049257      c68571ffffff.  mov byte [local_8fh], 0x2d  ; '-'
    |           0x0804925e      c68572ffffff.  mov byte [local_8eh], 0xbe
    |           0x08049265      c68573ffffff.  mov byte [local_8dh], 0x11
    |           0x0804926c      c68574ffffff.  mov byte [local_8ch], 0x1a
    |           0x08049273      c68575ffffff.  mov byte [local_8bh], 0xc3
    |           0x0804927a      c68576ffffff.  mov byte [local_8ah], 0x6a  ; 'j'
    |           0x08049281      c68577ffffff.  mov byte [local_89h], 0xe
    |           0x08049288      c68578ffffff.  mov byte [local_88h], 0x68  ; 'h'
    |           0x0804928f      c68579ffffff.  mov byte [local_87h], 0xa5
    |           0x08049296      c6857affffff.  mov byte [local_86h], 0x97
    |           0x0804929d      c6857bffffff.  mov byte [local_85h], 0x4d  ; 'M'
    |           0x080492a4      c6857cffffff.  mov byte [local_84h], 0xa1
    |           0x080492ab      c6857dffffff.  mov byte [local_83h], 5
    |           0x080492b2      c6857effffff.  mov byte [local_82h], 0x45  ; 'E'
    |           0x080492b9      c6857fffffff.  mov byte [local_81h], 0x49  ; 'I'
    |           0x080492c0      c6458039       mov byte [local_80h], 0x39  ; '9'
    |           0x080492c4      c645817b       mov byte [local_7fh], 0x7b  ; '{'
    |           0x080492c8      c64582c7       mov byte [local_7eh], 0xc7
    |           0x080492cc      c6458367       mov byte [local_7dh], 0x67  ; 'g'
    |           0x080492d0      c6458418       mov byte [local_7ch], 0x18
    |           0x080492d4      c6458515       mov byte [local_7bh], 0x15
    |           0x080492d8      c6458646       mov byte [local_7ah], 0x46  ; 'F'
    |           0x080492dc      c645875b       mov byte [local_79h], 0x5b  ; '['
    |           0x080492e0      c745e0d03574.  mov dword [local_20h], 0x1a7435d0
    |           0x080492e7      c68556ffffff.  mov byte [local_aah], 0xab
    |           0x080492ee      c68557ffffff.  mov byte [local_a9h], 0xeb
    |           0x080492f5      c68558ffffff.  mov byte [local_a8h], 0x77  ; 'w'
    |           0x080492fc      c68559ffffff.  mov byte [local_a7h], 0x6f  ; 'o'
    |           0x08049303      c6855affffff.  mov byte [local_a6h], 0xe9
    |           0x0804930a      c6855bffffff.  mov byte [local_a5h], 0xd5
    |           0x08049311      c6855cffffff.  mov byte [local_a4h], 0x97
    |           0x08049318      c6855dffffff.  mov byte [local_a3h], 0x2a  ; '*'
    |           0x0804931f      c6855effffff.  mov byte [local_a2h], 0x3c  ; '<'
    |           0x08049326      c6855fffffff.  mov byte [local_a1h], 0xed
    |           0x0804932d      c68560ffffff.  mov byte [local_a0h], 0x7a  ; 'z'
    |           0x08049334      c68561ffffff.  mov byte [local_9fh], 0xc
    |           0x0804933b      c68562ffffff.  mov byte [local_9eh], 0xf6
    |           0x08049342      c68563ffffff.  mov byte [local_9dh], 0xa8
    |           0x08049349      c745dc0e0000.  mov dword [local_24h], 0xe
    |           0x08049350      c745e4000000.  mov dword [local_1ch], 0
    |           0x08049357      83ec08         sub esp, 8
    |           0x0804935a      6a18           push 0x18                   ; " \x88\x04\b4"
    |           0x0804935c      6a01           push 1                      ; "ELF\x01\x01\x01"
    |           0x0804935e      e8adf4ffff     call sym.imp.calloc         ; void *calloc(size_t nmeb, size_t size)
    |           0x08049363      83c410         add esp, 0x10
    |           0x08049366      8945d8         mov dword [local_28h], eax
    |           0x08049369      837dd800       cmp dword [local_28h], 0
    |       ,=< 0x0804936d      752b           jne 0x804939a
    |       |   0x0804936f      e80cf4ffff     call sym.imp.__errno_location
    |       |   0x08049374      8b00           mov eax, dword [eax]
    |       |   0x08049376      c745c8ffffff.  mov dword [local_38h], 0xffffffff
    |       |   0x0804937d      8945c4         mov dword [local_3ch], eax
    |       |   0x08049380      c745c0c3a604.  mov dword [local_40h], 0x804a6c3
    |       |   0x08049387      6a18           push 0x18                   ; " \x88\x04\b4"
    |       |   0x08049389      ff75c0         push dword [local_40h]
    |       |   0x0804938c      ff75c4         push dword [local_3ch]
    |       |   0x0804938f      ff75c8         push dword [local_38h]
    |       |   0x08049392      e859f3ffff     call sym.imp.error
    |       |   0x08049397      83c410         add esp, 0x10
    |       |      ; JMP XREF from 0x0804936d (sym.check_flag_4)
    |       `-> 0x0804939a      e8f1f3ffff     call sym.imp.fork
    |           0x0804939f      8945d4         mov dword [local_2ch], eax
    |           0x080493a2      837dd400       cmp dword [local_2ch], 0
    |       ,=< 0x080493a6      0f85e0000000   jne 0x804948c
    |       |   0x080493ac      6a00           push 0
    |       |   0x080493ae      6a00           push 0
    |       |   0x080493b0      6a00           push 0
    |       |   0x080493b2      6a00           push 0
    |       |   0x080493b4      e827f4ffff     call sym.imp.ptrace
    |       |   0x080493b9      83c410         add esp, 0x10
    |       |   0x080493bc      cc             int3
            |   0x080493bd      8b45d8         mov eax, dword [ebp - 0x28]
            |   0x080493c0      8b55dc         mov edx, dword [ebp - 0x24]
            |   0x080493c3      8910           mov dword [eax], edx
            |   0x080493c5      8b45d8         mov eax, dword [ebp - 0x28]
            |   0x080493c8      8b55e0         mov edx, dword [ebp - 0x20]
            |   0x080493cb      895010         mov dword [eax + 0x10], edx
            |   0x080493ce      8b45d8         mov eax, dword [ebp - 0x28]
            |   0x080493d1      8d9556ffffff   lea edx, [ebp - 0xaa]
            |   0x080493d7      89500c         mov dword [eax + 0xc], edx
            |   0x080493da      83ec0c         sub esp, 0xc
            |   0x080493dd      ff75d8         push dword [ebp - 0x28]
            |   0x080493e0      e8fb070000     call sym.xorscura_decrypt
            |   0x080493e5      83c410         add esp, 0x10
            |   0x080493e8      83f8ff         cmp eax, 0xffffffffffffffff
           ,==< 0x080493eb      752d           jne 0x804941a
           ||   0x080493ed      8b5dd8         mov ebx, dword [ebp - 0x28]
           ||   0x080493f0      e88bf3ffff     call sym.imp.__errno_location
           ||   0x080493f5      8b00           mov eax, dword [eax]
           ||   0x080493f7      c745bcffffff.  mov dword [ebp - 0x44], 0xffffffff
           ||   0x080493fe      8945b8         mov dword [ebp - 0x48], eax
           ||   0x08049401      c745b4d1a604.  mov dword [ebp - 0x4c], str.xorscura_decrypt__lx_
           ||   0x08049408      53             push ebx
           ||   0x08049409      ff75b4         push dword [ebp - 0x4c]
           ||   0x0804940c      ff75b8         push dword [ebp - 0x48]
           ||   0x0804940f      ff75bc         push dword [ebp - 0x44]
           ||   0x08049412      e8d9f2ffff     call sym.imp.error
           ||   0x08049417      83c410         add esp, 0x10
           ||      ; JMP XREF from 0x080493eb (sym.check_flag_4 + 525)
           `--> 0x0804941a      8b45d8         mov eax, dword [ebp - 0x28]
            |   0x0804941d      8b4004         mov eax, dword [eax + 4]    ; [0x4:4]=0x10101
            |   0x08049420      83ec08         sub esp, 8
            |   0x08049423      6a00           push 0
            |   0x08049425      50             push eax
            |   0x08049426      e815f3ffff     call sym.imp.open           ; int open(const char *path, int oflag)
            |   0x0804942b      83c410         add esp, 0x10
            |   0x0804942e      8945cc         mov dword [ebp - 0x34], eax
            |   0x08049431      83ec04         sub esp, 4
            |   0x08049434      6a02           push 2                      ; "LF\x01\x01\x01"
            |   0x08049436      6af5           push 0xfffffffffffffff5
            |   0x08049438      ff75cc         push dword [ebp - 0x34]
            |   0x0804943b      e860f2ffff     call sym.imp.lseek
            |   0x08049440      83c410         add esp, 0x10
            |   0x08049443      83ec04         sub esp, 4
            |   0x08049446      6a0b           push 0xb
            |   0x08049448      8d854bffffff   lea eax, [ebp - 0xb5]
            |   0x0804944e      50             push eax
            |   0x0804944f      ff75cc         push dword [ebp - 0x34]
            |   0x08049452      e809f2ffff     call sym.imp.read           ; ssize_t read(int fildes, void *buf, size_t nbyte)
            |   0x08049457      83c410         add esp, 0x10
            |   0x0804945a      83ec04         sub esp, 4
            |   0x0804945d      6a0a           push 0xa
            |   0x0804945f      6a00           push 0
            |   0x08049461      8d854bffffff   lea eax, [ebp - 0xb5]
            |   0x08049467      50             push eax
            |   0x08049468      e863f3ffff     call sym.imp.strtol         ; long strtol(const char *str, char**endptr, int base)
            |   0x0804946d      83c410         add esp, 0x10
            |   0x08049470      894588         mov dword [ebp - 0x78], eax
            |   0x08049473      83ec0c         sub esp, 0xc
            |   0x08049476      ff75cc         push dword [ebp - 0x34]
            |   0x08049479      e872f3ffff     call sym.imp.close          ; int close(int fildes)
            |   0x0804947e      83c410         add esp, 0x10
            |   0x08049481      cc             int3
            |   0x08049482      83ec0c         sub esp, 0xc
            |   0x08049485      6a00           push 0
            |   0x08049487      e8a4f2ffff     call sym.imp.exit           ; void exit(int status)
    |       |      ; JMP XREF from 0x080493a6 (sym.check_flag_4)
    |       `-> 0x0804948c      83ec0c         sub esp, 0xc
    |           0x0804948f      6a00           push 0
    |           0x08049491      e82af2ffff     call sym.imp.wait
    |           0x08049496      83c410         add esp, 0x10
    |           0x08049499      6a00           push 0
    |           0x0804949b      6a00           push 0
    |           0x0804949d      ff75d4         push dword [local_2ch]
    |           0x080494a0      6a10           push 0x10
    |           0x080494a2      e839f3ffff     call sym.imp.ptrace
    |           0x080494a7      83c410         add esp, 0x10
    |           0x080494aa      6a00           push 0
    |           0x080494ac      6a00           push 0
    |           0x080494ae      ff75d4         push dword [local_2ch]
    |           0x080494b1      6a07           push 7
    |           0x080494b3      e828f3ffff     call sym.imp.ptrace
    |           0x080494b8      83c410         add esp, 0x10
    |           0x080494bb      83ec0c         sub esp, 0xc
    |           0x080494be      6a00           push 0
    |           0x080494c0      e8fbf1ffff     call sym.imp.wait
    |           0x080494c5      83c410         add esp, 0x10
    |           0x080494c8      6a00           push 0
    |           0x080494ca      8d4588         lea eax, [local_78h]
    |           0x080494cd      50             push eax
    |           0x080494ce      ff75d4         push dword [local_2ch]
    |           0x080494d1      6a02           push 2                      ; "LF\x01\x01\x01"
    |           0x080494d3      e808f3ffff     call sym.imp.ptrace
    |           0x080494d8      83c410         add esp, 0x10
    |           0x080494db      894588         mov dword [local_78h], eax
    |           0x080494de      6a00           push 0
    |           0x080494e0      6a00           push 0
    |           0x080494e2      ff75d4         push dword [local_2ch]
    |           0x080494e5      6a11           push 0x11
    |           0x080494e7      e8f4f2ffff     call sym.imp.ptrace
    |           0x080494ec      83c410         add esp, 0x10
    |           0x080494ef      83ec0c         sub esp, 0xc
    |           0x080494f2      6a00           push 0
    |           0x080494f4      e8c7f1ffff     call sym.imp.wait
    |           0x080494f9      83c410         add esp, 0x10
    |           0x080494fc      8b45d8         mov eax, dword [local_28h]
    |           0x080494ff      c70024000000   mov dword [eax], 0x24       ; '$' ; [0x24:4]=0 ; '$'
    |           0x08049505      8b5588         mov edx, dword [local_78h]
    |           0x08049508      8b45d8         mov eax, dword [local_28h]
    |           0x0804950b      895010         mov dword [eax + 0x10], edx
    |           0x0804950e      8b45d8         mov eax, dword [local_28h]
    |           0x08049511      8d9564ffffff   lea edx, [local_9ch]
    |           0x08049517      89500c         mov dword [eax + 0xc], edx
    |           0x0804951a      8b45d8         mov eax, dword [local_28h]
    |           0x0804951d      8b13           mov edx, dword [ebx]
    |           0x0804951f      895004         mov dword [eax + 4], edx
    |           0x08049522      83ec0c         sub esp, 0xc
    |           0x08049525      ff75d8         push dword [local_28h]
    |           0x08049528      e893080000     call sym.xorscura_compare
    |           0x0804952d      83c410         add esp, 0x10
    |           0x08049530      8945d0         mov dword [local_30h], eax
    |           0x08049533      837dd0ff       cmp dword [local_30h], 0xffffffffffffffff
    |       ,=< 0x08049537      752d           jne 0x8049566
    |       |   0x08049539      8b5dd8         mov ebx, dword [local_28h]
    |       |   0x0804953c      e83ff2ffff     call sym.imp.__errno_location
    |       |   0x08049541      8b00           mov eax, dword [eax]
    |       |   0x08049543      c745b0ffffff.  mov dword [local_50h], 0xffffffff
    |       |   0x0804954a      8945ac         mov dword [local_54h], eax
    |       |   0x0804954d      c745a8e7a604.  mov dword [local_58h], 0x804a6e7
    |       |   0x08049554      53             push ebx
    |       |   0x08049555      ff75a8         push dword [local_58h]
    |       |   0x08049558      ff75ac         push dword [local_54h]
    |       |   0x0804955b      ff75b0         push dword [local_50h]
    |       |   0x0804955e      e88df1ffff     call sym.imp.error
    |       |   0x08049563      83c410         add esp, 0x10
    |       |      ; JMP XREF from 0x08049537 (sym.check_flag_4)
    |       `-> 0x08049566      837dd000       cmp dword [local_30h], 0
    |       ,=< 0x0804956a      7507           jne 0x8049573
    |       |   0x0804956c      c745e4010000.  mov dword [local_1ch], 1
    |       |      ; JMP XREF from 0x0804956a (sym.check_flag_4)
    |       `-> 0x08049573      83ec0c         sub esp, 0xc
    |           0x08049576      ff75d8         push dword [local_28h]
    |           0x08049579      e8d2080000     call sym.xorscura_free_xod  ; void free(void *ptr)
    |           0x0804957e      83c410         add esp, 0x10
    |           0x08049581      83ec0c         sub esp, 0xc
    |           0x08049584      ff75d8         push dword [local_28h]
    |           0x08049587      e8f4f0ffff     call sym.imp.free           ; void free(void *ptr)
    |           0x0804958c      83c410         add esp, 0x10
    |           0x0804958f      8b45e4         mov eax, dword [local_1ch]
    |           0x08049592      8d65f8         lea esp, [local_8h]
    |           0x08049595      59             pop ecx
    |           0x08049596      5b             pop ebx
    |           0x08049597      5d             pop ebp
    |           0x08049598      8d61fc         lea esp, [ecx - 4]
    \           0x0804959b      c3             ret
    

This function just looks annoying, what with the opens and ptrace() and all this.. stuff going on. Also the fork(), meaning I'd have to learn how to have gdb debug child processes as well. All of that sounds annoying, but here's an idea: this still calls xorscura_compare(). And, it turns out check_flag_5 also calls xorscura_compare(). So let's put this fork/ptrace business aside a moment and look at that.

Now, avoiding the anti-debug tricks is annoying. Wouldn't it be easier if the program just printed out the flag bytes?

How could we make that happen?

puts() to the rescue

I noticed earlier that puts() is used in main(), and it has a dead-simple interface. Pass it a pointer, it prints characters until it reaches a null.

Flags here are available 1-4 bytes at a time, but tinkering with imports to get putchar exposed is absolutely not how I wanted to spend time - puts()'ing the flag one byte at a time is plenty good for CTF.

How can we cram a puts() call in though? Calls are large (5 byte) instructions, and we only have a few bytes to work with from the cmp and corresponding jne.

.. Or do we? If we assume inputs are all multiples of 4 (which they are, because flags are multiples of 4 and we'll just type in the right stuff), we can remove all the lea eax, [ebx + N]; cmp edx, eax; je 0x8049da0. That lets us go from 4 bytes to 11 bytes to work with. We can even discard the user input string entirely and consider movzx ebp, byte [edi + ebx + 1] space up for grabs too. That puts us at 16 bytes of code space to mess with for each byte of the flag we want to print, with four bytes we want to print.

no matter what we need to be careful to not clobber registers

So what registers are preserved by the ABI? That is, what do we have to worry about being trashed by putting in a random puts() or four?

ebx, esi, edi, ebp, and esp

At each of these xor, edi, esi, edx, ecx, ebx, and eax are used.

So we have to worry about edx, ecx, and eax. Push/pop are one byte each, call is five, for a total of 11 bytes if we can arrange the stack right. This isn't quite small enough.

Maybe we can move one of these values into a register that won't be trashed by puts()? We won't be using edi anymore, which was used for the user-input flag string. So let's patch the mov edx, dword [esi] into a mov edi, dword [esi] instead, saving us two bytes in future patches, making this insanity workable! In addition, we'll need to patch cmp at 0x8049d01, 0x8049d21, 0x8049d3d, and 0x8049d59 to all use edi instead of edx. Respectively, they change to 39c7, 39c7, 39c7, and 39fd. The mov at 0x8049cfc also will turn into 8b3e.

For some reason, the compiler decided to put the last value of each loop in edi instead of ebp, but that doesn't matter because we'll overwrite that soon anyway.

What's the nicest way to get the current flag byte at a pointer to print, though? In these, probably prefixing a call puts() with push eax, push esp. eax already having the character to compare to for the flag, esp then being a pointer to it for puts().

We can take advantage of eax being an argument to only push it once, meaning at the end of it we'll want write in something that calls puts() but also preserves registers that have values that will be used - ebx, ecx, and esp. ebx and esp are preserved by the ABI, so we only have to save ecx ourselves. I went with something like push ecx; push eax; push esp; call sym.puts; pop eax; pop eax; pop ecx. This gives us a total of 11 bytes of code to insert, so let's see if that's small enough...

In xorscura_compare_prng() we'll want to patch at 0x8049ce9, 0x8049d0e, 0x8049d2a, and 0x8049d46. For all of these, we'll want to retain the xor al, byte [...] and move it up appropriately so the printed character is still decoded!

If we're just patching out the comparison, the cmp at 0x8049cf4, 0x8049d1a, 0x8049d38, and 0x8049d54 aren't necessary anymore, nor are the movzx into ebp or edx for the user input string to check against. We can also remove the jne for when the strings are not equal too. That puts us at 4 + 3 + 2 + 6 = 15 bytes to work with in the first region, and 5 + 3 + 2 + 2 = 12 bytes in the others. The other comparisons against ebx + 1, ebx + 2, ebx + 3 are to check bounds against input sizes - since inputs are multiples of four we don't need these, but not removing them means less work. So let's not. The patch itself is 11 bytes, so this fits nicely as long as we move some code around.

0x8049ce9

The compiler used 0f85 and 0f84 for jne and je by 0x8049ce9 because the jump targets are >128 bytes forward, so we have a little extra room to work with here, but it's not actually too important.

Here we'll want to rewrite right after the movzx eax, byte [ecx + ebx], writing in: xor al, byte [esp + 0x1c] push ecx push eax push esp call sym.puts ; more on this in a moment pop eax ; to fix up the stack pop eax ; restore eax pop ecx ; restore ecx

This assembles to 3244241c515054e8XXXXXXXX585859, for 15 bytes. At 0x8049ce9 we have 0fb6141f3244241c0fbec039c20f8584000000, 19 bytes, so let's throw 66666690 at the end for a nop to fill the extra space.

XXXXXXXX is an offset to the start of puts(). Or, more specifically, where the loader fixed up a jmp to go to puts()

I'm not sure where that would be, so the easiest thing I imagined was to look at what another puts() goes. Say, the one in main sounds good!

0x08048b94      e867fbffff     call sym.imp.puts

The offset here is 0xfffffb67, and the call destination is that offset plus the address of this instruction, plus the length of this instruction, which comes out to 0x8048b94 + 0xfffffb67 + 5, for our puts() target being at 0x8048700. So in our patch, we'll want XXXXXXXX to be 0x8048700 - (0x8049cf0 + 5), for 0xffffea0b. Because little-endian, the whole instruction is written out as e80beaffff.

Now we have a patch! 3244241c515054e80beaffff58585966666690 @ 0x8049ce9.

0x8049d0e

Same process holds here, too. Same patch fits, but the nop at the end will have to be differently sized to fit in the space - just 90 instead of the four byte version, here and for the next two.

We also need to be careful to xor against esp + 0x1d here, not esp + 0x1c again.

Repeating the process for computing a call destination, we get our patch: 3244241d515054e8e6e9ffff58585990 @ 0x8049d0e

0x8049d2a

Again, next byte from random_r(), so xor al, byte [esp + 0x1e]

Same size region, so we just have to figure out the call destination here: 3244241e515054e8cae9ffff58585990 @ 0x8049d2a

0x8049d46

Yadda yadda yadda, xor against next byte, spoiler alert: 3244241f515054e8aee9ffff58585990 @ 0x8049d46

Aaaand patch!

Before:
       ,==< 0x08049cd9      0f84d1000000   je 0x8049db0
           ||   0x08049cdf      8b4e0c         mov ecx, dword [esi + 0xc]  ; [0xc:4]=0
           ||   0x08049ce2      8b7e04         mov edi, dword [esi + 4]    ; [0x4:4]=0x10101
           ||   0x08049ce5      0fb60419       movzx eax, byte [ecx + ebx]
           ||   0x08049ce9      0fb6141f       movzx edx, byte [edi + ebx]
           ||   0x08049ced      3244241c       xor al, byte [esp + 0x1c]
           ||   0x08049cf1      0fbec0         movsx eax, al
           ||   0x08049cf4      39c2           cmp edx, eax
          ,===< 0x08049cf6      0f8584000000   jne 0x8049d80
          |||   0x08049cfc      8b16           mov edx, dword [esi]
          |||   0x08049cfe      8d4301         lea eax, [ebx + 1]
          |||   0x08049d01      39c2           cmp edx, eax
         ,====< 0x08049d03      0f8497000000   je 0x8049da0
         ||||   0x08049d09      0fb6441901     movzx eax, byte [ecx + ebx + 1] ; [0x1:1]=69
         ||||   0x08049d0e      0fb66c1f01     movzx ebp, byte [edi + ebx + 1] ; [0x1:1]=69
         ||||   0x08049d13      3244241d       xor al, byte [esp + 0x1d]
         ||||   0x08049d17      0fbec0         movsx eax, al
         ||||   0x08049d1a      39c5           cmp ebp, eax
        ,=====< 0x08049d1c      7562           jne 0x8049d80
        |||||   0x08049d1e      8d4302         lea eax, [ebx + 2]
        |||||   0x08049d21      39c2           cmp edx, eax
       ,======< 0x08049d23      747b           je 0x8049da0
       ||||||   0x08049d25      0fb6441902     movzx eax, byte [ecx + ebx + 2] ; [0x2:1]=76
       ||||||   0x08049d2a      0fb66c1f02     movzx ebp, byte [edi + ebx + 2] ; [0x2:1]=76
       ||||||   0x08049d2f      3244241e       xor al, byte [esp + 0x1e]
       ||||||   0x08049d33      0fbec0         movsx eax, al
       ||||||   0x08049d36      39c5           cmp ebp, eax
      ,=======< 0x08049d38      7546           jne 0x8049d80
      |||||||   0x08049d3a      8d4303         lea eax, [ebx + 3]          ; "F\x01\x01\x01"
      |||||||   0x08049d3d      39c2           cmp edx, eax
      ========< 0x08049d3f      745f           je 0x8049da0
      |||||||   0x08049d41      0fb6441903     movzx eax, byte [ecx + ebx + 3] ; [0x3:1]=70 ; "F\x01\x01\x01"
      |||||||   0x08049d46      0fb67c1f03     movzx edi, byte [edi + ebx + 3] ; [0x3:1]=70 ; "F\x01\x01\x01"
      |||||||   0x08049d4b      3244241f       xor al, byte [esp + 0x1f]
      |||||||   0x08049d4f      0fbec0         movsx eax, al
      |||||||   0x08049d52      39c7           cmp edi, eax
      ========< 0x08049d54      752a           jne 0x8049d80
      |||||||   0x08049d56      83c304         add ebx, 4
      |||||||   0x08049d59      39d3           cmp ebx, edx
      ||||||`=< 0x08049d5b      0f8261ffffff   jb 0x8049cc2
      ||||||    0x08049d61      83ec0c         sub esp, 0xc
      ||||||    0x08049d64      ff742418       push dword [esp + 0x18]
      ||||||    0x08049d68      e813e9ffff     call sym.imp.free
      ||||||    0x08049d6d      83c410         add esp, 0x10
      ||||||    0x08049d70      31c0           xor eax, eax
      ||||||    0x08049d72      81c42c010000   add esp, 0x12c
      ||||||    0x08049d78      5b             pop ebx
      ||||||    0x08049d79      5e             pop esi
      ||||||    0x08049d7a      5f             pop edi
      ||||||    0x08049d7b      5d             pop ebp
      ||||||    0x08049d7c      c3             ret
     -- Find wide-char strings with the '/w <string>' command
    
    
    [0x08048820]> 
After:
        ,=< 0x08049cd9      0f84d1000000   je 0x8049db0
            |   0x08049cdf      8b4e0c         mov ecx, dword [esi + 0xc]  ; [0xc:4]=0
            |   0x08049ce2      8b7e04         mov edi, dword [esi + 4]    ; [0x4:4]=0x10101
            |   0x08049ce5      0fb60419       movzx eax, byte [ecx + ebx]
            |   0x08049ce9      3244241c       xor al, byte [esp + 0x1c]
            |   0x08049ced      51             push ecx
            |   0x08049cee      50             push eax
            |   0x08049cef      54             push esp
            |   0x08049cf0      e80beaffff     call sym.imp.puts
            |   0x08049cf5      58             pop eax
            |   0x08049cf6      58             pop eax
            |   0x08049cf7      59             pop ecx
            |   0x08049cf8      66666690       nop
            |   0x08049cfc      8b16           mov edx, dword [esi]
            |   0x08049cfe      8d4301         lea eax, [ebx + 1]
            |   0x08049d01      39c2           cmp edx, eax
           ,==< 0x08049d03      0f8497000000   je 0x8049da0
           ||   0x08049d09      0fb6441901     movzx eax, byte [ecx + ebx + 1] ; [0x1:1]=69
           ||   0x08049d0e      3244241d       xor al, byte [esp + 0x1d]
           ||   0x08049d12      51             push ecx
           ||   0x08049d13      50             push eax
           ||   0x08049d14      54             push esp
           ||   0x08049d15      e8e6e9ffff     call sym.imp.puts
           ||   0x08049d1a      58             pop eax
           ||   0x08049d1b      58             pop eax
           ||   0x08049d1c      59             pop ecx
           ||   0x08049d1d      90             nop
           ||   0x08049d1e      8d4302         lea eax, [ebx + 2]
           ||   0x08049d21      39c2           cmp edx, eax
          ,===< 0x08049d23      747b           je 0x8049da0
          |||   0x08049d25      0fb6441902     movzx eax, byte [ecx + ebx + 2] ; [0x2:1]=76
          |||   0x08049d2a      3244241e       xor al, byte [esp + 0x1e]
          |||   0x08049d2e      51             push ecx
          |||   0x08049d2f      50             push eax
          |||   0x08049d30      54             push esp
          |||   0x08049d31      e8cae9ffff     call sym.imp.puts
          |||   0x08049d36      58             pop eax
          |||   0x08049d37      58             pop eax
          |||   0x08049d38      59             pop ecx
          |||   0x08049d39      90             nop
          |||   0x08049d3a      8d4303         lea eax, [ebx + 3]          ; "F\x01\x01\x01"
          |||   0x08049d3d      39c2           cmp edx, eax
         ,====< 0x08049d3f      745f           je 0x8049da0
         ||||   0x08049d41      0fb6441903     movzx eax, byte [ecx + ebx + 3] ; [0x3:1]=70 ; "F\x01\x01\x01"
         ||||   0x08049d46      3244241f       xor al, byte [esp + 0x1f]
         ||||   0x08049d4a      51             push ecx
         ||||   0x08049d4b      50             push eax
         ||||   0x08049d4c      54             push esp
         ||||   0x08049d4d      e8aee9ffff     call sym.imp.puts
         ||||   0x08049d52      58             pop eax
         ||||   0x08049d53      58             pop eax
    

Wonderful - they are in fact correctly lined up calls to puts(), everything seems to line up... Now we should be able to run the program and, regardless of input, it'll print out flags.

Well, it does.

+400

Flag 5

/ (fcn) sym.check_flag_5 710
    |   sym.check_flag_5 ();
    |           ; var int local_8h @ ebp-0x8
    |           ; var int local_40h @ ebp-0x40
    |           ; var int local_3ch @ ebp-0x3c
    |           ; var int local_38h @ ebp-0x38
    |           ; var int local_28h @ ebp-0x28
    |           ; var int local_34h @ ebp-0x34
    |           ; var int local_30h @ ebp-0x30
    |           ; var int local_2ch @ ebp-0x2c
    |           ; var int local_24h @ ebp-0x24
    |           ; var int local_98h @ ebp-0x98
    |           ; var int local_1ch @ ebp-0x1c
    |           ; var int local_65h @ ebp-0x65
    |           ; var int local_66h @ ebp-0x66
    |           ; var int local_67h @ ebp-0x67
    |           ; var int local_68h @ ebp-0x68
    |           ; var int local_69h @ ebp-0x69
    |           ; var int local_6ah @ ebp-0x6a
    |           ; var int local_6bh @ ebp-0x6b
    |           ; var int local_6ch @ ebp-0x6c
    |           ; var int local_6dh @ ebp-0x6d
    |           ; var int local_6eh @ ebp-0x6e
    |           ; var int local_6fh @ ebp-0x6f
    |           ; var int local_70h @ ebp-0x70
    |           ; var int local_71h @ ebp-0x71
    |           ; var int local_72h @ ebp-0x72
    |           ; var int local_73h @ ebp-0x73
    |           ; var int local_74h @ ebp-0x74
    |           ; var int local_75h @ ebp-0x75
    |           ; var int local_76h @ ebp-0x76
    |           ; var int local_77h @ ebp-0x77
    |           ; var int local_78h @ ebp-0x78
    |           ; var int local_79h @ ebp-0x79
    |           ; var int local_7ah @ ebp-0x7a
    |           ; var int local_7bh @ ebp-0x7b
    |           ; var int local_7ch @ ebp-0x7c
    |           ; var int local_7dh @ ebp-0x7d
    |           ; var int local_7eh @ ebp-0x7e
    |           ; var int local_7fh @ ebp-0x7f
    |           ; var int local_80h @ ebp-0x80
    |           ; var int local_81h @ ebp-0x81
    |           ; var int local_82h @ ebp-0x82
    |           ; var int local_83h @ ebp-0x83
    |           ; var int local_84h @ ebp-0x84
    |           ; var int local_85h @ ebp-0x85
    |           ; var int local_86h @ ebp-0x86
    |           ; var int local_87h @ ebp-0x87
    |           ; var int local_88h @ ebp-0x88
    |           ; var int local_41h @ ebp-0x41
    |           ; var int local_42h @ ebp-0x42
    |           ; var int local_43h @ ebp-0x43
    |           ; var int local_44h @ ebp-0x44
    |           ; var int local_45h @ ebp-0x45
    |           ; var int local_46h @ ebp-0x46
    |           ; var int local_47h @ ebp-0x47
    |           ; var int local_48h @ ebp-0x48
    |           ; var int local_49h @ ebp-0x49
    |           ; var int local_4ah @ ebp-0x4a
    |           ; var int local_4bh @ ebp-0x4b
    |           ; var int local_4ch @ ebp-0x4c
    |           ; var int local_4dh @ ebp-0x4d
    |           ; var int local_4eh @ ebp-0x4e
    |           ; var int local_4fh @ ebp-0x4f
    |           ; var int local_50h @ ebp-0x50
    |           ; var int local_51h @ ebp-0x51
    |           ; var int local_52h @ ebp-0x52
    |           ; var int local_53h @ ebp-0x53
    |           ; var int local_54h @ ebp-0x54
    |           ; var int local_55h @ ebp-0x55
    |           ; var int local_56h @ ebp-0x56
    |           ; var int local_57h @ ebp-0x57
    |           ; var int local_58h @ ebp-0x58
    |           ; var int local_59h @ ebp-0x59
    |           ; var int local_5ah @ ebp-0x5a
    |           ; var int local_5bh @ ebp-0x5b
    |           ; var int local_5ch @ ebp-0x5c
    |           ; var int local_5dh @ ebp-0x5d
    |           ; var int local_5eh @ ebp-0x5e
    |           ; var int local_5fh @ ebp-0x5f
    |           ; var int local_60h @ ebp-0x60
    |           ; var int local_61h @ ebp-0x61
    |           ; var int local_62h @ ebp-0x62
    |           ; var int local_63h @ ebp-0x63
    |           ; var int local_64h @ ebp-0x64
    |           ; var int local_4h @ esp+0x4
    |              ; CALL XREF from 0x08048b2f (sym.main)
    |           0x0804959c      8d4c2404       lea ecx, [local_4h]
    |           0x080495a0      83e4e0         and esp, 0xffffffe0
    |           0x080495a3      ff71fc         push dword [ecx - 4]
    |           0x080495a6      55             push ebp
    |           0x080495a7      89e5           mov ebp, esp
    |           0x080495a9      53             push ebx
    |           0x080495aa      51             push ecx
    |           0x080495ab      81ec90000000   sub esp, 0x90
    |           0x080495b1      89cb           mov ebx, ecx
    |           0x080495b3      c6459ccd       mov byte [local_64h], 0xcd
    |           0x080495b7      c6459d2a       mov byte [local_63h], 0x2a  ; '*'
    |           0x080495bb      c6459e8b       mov byte [local_62h], 0x8b
    |           0x080495bf      c6459f3f       mov byte [local_61h], 0x3f  ; '?'
    |           0x080495c3      c645a09d       mov byte [local_60h], 0x9d
    |           0x080495c7      c645a18a       mov byte [local_5fh], 0x8a
    |           0x080495cb      c645a28d       mov byte [local_5eh], 0x8d
    |           0x080495cf      c645a33e       mov byte [local_5dh], 0x3e  ; '>'
    |           0x080495d3      c645a464       mov byte [local_5ch], 0x64  ; 'd'
    |           0x080495d7      c645a55a       mov byte [local_5bh], 0x5a  ; 'Z'
    |           0x080495db      c645a683       mov byte [local_5ah], 0x83
    |           0x080495df      c645a74f       mov byte [local_59h], 0x4f  ; 'O'
    |           0x080495e3      c645a87c       mov byte [local_58h], 0x7c  ; '|'
    |           0x080495e7      c645a950       mov byte [local_57h], 0x50  ; 'P'
    |           0x080495eb      c645aab9       mov byte [local_56h], 0xb9
    |           0x080495ef      c645ab32       mov byte [local_55h], 0x32  ; '2'
    |           0x080495f3      c645acd2       mov byte [local_54h], 0xd2
    |           0x080495f7      c645adfe       mov byte [local_53h], 0xfe
    |           0x080495fb      c645ae3b       mov byte [local_52h], 0x3b  ; ';'
    |           0x080495ff      c645af1a       mov byte [local_51h], 0x1a
    |           0x08049603      c645b03c       mov byte [local_50h], 0x3c  ; '<'
    |           0x08049607      c645b198       mov byte [local_4fh], 0x98
    |           0x0804960b      c645b26d       mov byte [local_4eh], 0x6d  ; 'm'
    |           0x0804960f      c645b33b       mov byte [local_4dh], 0x3b  ; ';'
    |           0x08049613      c645b4b4       mov byte [local_4ch], 0xb4
    |           0x08049617      c645b5eb       mov byte [local_4bh], 0xeb
    |           0x0804961b      c645b660       mov byte [local_4ah], 0x60  ; '`'
    |           0x0804961f      c645b772       mov byte [local_49h], 0x72  ; 'r'
    |           0x08049623      c645b8f8       mov byte [local_48h], 0xf8
    |           0x08049627      c645b9f5       mov byte [local_47h], 0xf5
    |           0x0804962b      c645ba46       mov byte [local_46h], 0x46  ; 'F'
    |           0x0804962f      c645bb35       mov byte [local_45h], 0x35  ; '5'
    |           0x08049633      c645bca6       mov byte [local_44h], 0xa6
    |           0x08049637      c645bdce       mov byte [local_43h], 0xce
    |           0x0804963b      c645be70       mov byte [local_42h], 0x70  ; 'p'
    |           0x0804963f      c645bf6c       mov byte [local_41h], 0x6c  ; 'l'
    |           0x08049643      c68578ffffff.  mov byte [local_88h], 0x7d  ; '}'
    |           0x0804964a      c68579ffffff.  mov byte [local_87h], 0xf0
    |           0x08049651      c6857affffff.  mov byte [local_86h], 0xc5
    |           0x08049658      c6857bffffff.  mov byte [local_85h], 0x6a  ; 'j'
    |           0x0804965f      c6857cffffff.  mov byte [local_84h], 0x5c  ; '\'
    |           0x08049666      c6857dffffff.  mov byte [local_83h], 0xaa
    |           0x0804966d      c6857effffff.  mov byte [local_82h], 0x15
    |           0x08049674      c6857fffffff.  mov byte [local_81h], 0x63  ; 'c'
    |           0x0804967b      c645805e       mov byte [local_80h], 0x5e  ; '^'
    |           0x0804967f      c6458155       mov byte [local_7fh], 0x55  ; 'U'
    |           0x08049683      c6458237       mov byte [local_7eh], 0x37  ; '7'
    |           0x08049687      c645831f       mov byte [local_7dh], 0x1f
    |           0x0804968b      c6458406       mov byte [local_7ch], 6
    |           0x0804968f      c64585e2       mov byte [local_7bh], 0xe2
    |           0x08049693      c64586b8       mov byte [local_7ah], 0xb8
    |           0x08049697      c6458758       mov byte [local_79h], 0x58  ; 'X'
    |           0x0804969b      c64588f1       mov byte [local_78h], 0xf1
    |           0x0804969f      c64589fa       mov byte [local_77h], 0xfa
    |           0x080496a3      c6458aac       mov byte [local_76h], 0xac
    |           0x080496a7      c6458b4d       mov byte [local_75h], 0x4d  ; 'M'
    |           0x080496ab      c6458c24       mov byte [local_74h], 0x24  ; '$'
    |           0x080496af      c6458dd7       mov byte [local_73h], 0xd7
    |           0x080496b3      c6458ed3       mov byte [local_72h], 0xd3
    |           0x080496b7      c6458f22       mov byte [local_71h], 0x22  ; '"'
    |           0x080496bb      c6459064       mov byte [local_70h], 0x64  ; 'd'
    |           0x080496bf      c64591c1       mov byte [local_6fh], 0xc1
    |           0x080496c3      c6459283       mov byte [local_6eh], 0x83
    |           0x080496c7      c6459353       mov byte [local_6dh], 0x53  ; 'S'
    |           0x080496cb      c64594a3       mov byte [local_6ch], 0xa3
    |           0x080496cf      c6459531       mov byte [local_6bh], 0x31  ; '1'
    |           0x080496d3      c64596bf       mov byte [local_6ah], 0xbf
    |           0x080496d7      c645974b       mov byte [local_69h], 0x4b  ; 'K'
    |           0x080496db      c64598f0       mov byte [local_68h], 0xf0
    |           0x080496df      c64599c1       mov byte [local_67h], 0xc1
    |           0x080496e3      c6459a05       mov byte [local_66h], 5
    |           0x080496e7      c6459b03       mov byte [local_65h], 3
    |           0x080496eb      c745e4000000.  mov dword [local_1ch], 0
    |           0x080496f2      8d459c         lea eax, [local_64h]
    |           0x080496f5      898568ffffff   mov dword [local_98h], eax
    |           0x080496fb      666666666666.  nop
    |           0x08049707      666666666666.  nop
    |           0x08049714      90             nop
    |           0x08049715      90             nop
    |           0x08049716      90             nop
    |           0x08049717      90             nop
    |           0x08049718      90             nop
    |           0x08049719      90             nop
    |           0x0804971a      90             nop
    |           0x0804971b      90             nop
    |           0x0804971c      90             nop
    |           0x0804971d      90             nop
    |           0x0804971e      90             nop
    |           0x0804971f      90             nop
    |           0x08049720      90             nop
    |           0x08049721      90             nop
    |           0x08049722      90             nop
    |           0x08049723      90             nop
    |           0x08049724      90             nop
    |           0x08049725      90             nop
    |           0x08049726      90             nop
    |           0x08049727      90             nop
    |           0x08049728      90             nop
    |           0x08049729      90             nop
    |           0x0804972a      90             nop
    |           0x0804972b      90             nop
    |           0x0804972c      90             nop
    |           0x0804972d      90             nop
    |           0x0804972e      90             nop
    |           0x0804972f      90             nop
    |           0x08049730      90             nop
    |           0x08049731      90             nop
    |           0x08049732      90             nop
    |           0x08049733      90             nop
    |           0x08049734      90             nop
    |           0x08049735      90             nop
    |           0x08049736      6865980408     push 0x8049865
    |           0x0804973b      8d8568ffffff   lea eax, [local_98h]
    |           0x08049741      50             push eax
    |           0x08049742      58             pop eax
    |           0x08049743      5b             pop ebx
    |           0x08049744      8918           mov dword [eax], ebx
    |           0x08049746      90             nop
    |           0x08049747      90             nop
    |           0x08049748      90             nop
    |           0x08049749      90             nop
    |           0x0804974a      90             nop
    |           0x0804974b      90             nop
    |           0x0804974c      90             nop
    |           0x0804974d      90             nop
    |           0x0804974e      90             nop
    |           0x0804974f      90             nop
    |           0x08049750      90             nop
    |           0x08049751      90             nop
    |           0x08049752      90             nop
    |           0x08049753      90             nop
    |           0x08049754      90             nop
    |           0x08049755      90             nop
    |           0x08049756      90             nop
    |           0x08049757      90             nop
    |           0x08049758      90             nop
    |           0x08049759      90             nop
    |           0x0804975a      90             nop
    |           0x0804975b      90             nop
    |           0x0804975c      90             nop
    |           0x0804975d      90             nop
    |           0x0804975e      90             nop
    |           0x0804975f      90             nop
    |           0x08049760      90             nop
    |           0x08049761      90             nop
    |           0x08049762      90             nop
    |           0x08049763      90             nop
    |           0x08049764      90             nop
    |           0x08049765      90             nop
    |           0x08049766      90             nop
    |           0x08049767      90             nop
    |           0x08049768      90             nop
    |           0x08049769      90             nop
    |           0x0804976a      90             nop
    |           0x0804976b      90             nop
    |           0x0804976c      90             nop
    |           0x0804976d      90             nop
    |           0x0804976e      90             nop
    |           0x0804976f      90             nop
    |           0x08049770      90             nop
    |           0x08049771      90             nop
    |           0x08049772      90             nop
    |           0x08049773      90             nop
    |           0x08049774      90             nop
    |           0x08049775      90             nop
    |           0x08049776      90             nop
    |           0x08049777      90             nop
    |           0x08049778      90             nop
    |           0x08049779      90             nop
    |           0x0804977a      90             nop
    |           0x0804977b      90             nop
    |           0x0804977c      83ec08         sub esp, 8
    |           0x0804977f      6a18           push 0x18                   ; " \x88\x04\b4"
    |           0x08049781      6a01           push 1
    |           0x08049783      e888f0ffff     call sym.imp.calloc         ; void *calloc(size_t nmeb, size_t size)
    |           0x08049788      83c410         add esp, 0x10
    |           0x0804978b      8945dc         mov dword [local_24h], eax
    |           0x0804978e      837ddc00       cmp dword [local_24h], 0
    |       ,=< 0x08049792      752b           jne 0x80497bf
    |       |   0x08049794      e8e7efffff     call sym.imp.__errno_location
    |       |   0x08049799      8b00           mov eax, dword [eax]
    |       |   0x0804979b      c745d4ffffff.  mov dword [local_2ch], 0xffffffff
    |       |   0x080497a2      8945d0         mov dword [local_30h], eax
    |       |   0x080497a5      c745ccfda604.  mov dword [local_34h], str.calloc_1___d_
    |       |   0x080497ac      6a18           push 0x18                   ; " \x88\x04\b4"
    |       |   0x080497ae      ff75cc         push dword [local_34h]
    |       |   0x080497b1      ff75d0         push dword [local_30h]
    |       |   0x080497b4      ff75d4         push dword [local_2ch]
    |       |   0x080497b7      e834efffff     call sym.imp.error
    |       |   0x080497bc      83c410         add esp, 0x10
    |       |      ; JMP XREF from 0x08049792 (sym.check_flag_5)
    |       `-> 0x080497bf      8b45dc         mov eax, dword [local_24h]
    |           0x080497c2      c70024000000   mov dword [eax], 0x24       ; '$' ; [0x24:4]=0 ; '$'
    |           0x080497c8      8b9568ffffff   mov edx, dword [local_98h]
    |           0x080497ce      8b45dc         mov eax, dword [local_24h]
    |           0x080497d1      895008         mov dword [eax + 8], edx
    |           0x080497d4      8b45dc         mov eax, dword [local_24h]
    |           0x080497d7      8d9578ffffff   lea edx, [local_88h]
    |           0x080497dd      89500c         mov dword [eax + 0xc], edx
    |           0x080497e0      8b45dc         mov eax, dword [local_24h]
    |           0x080497e3      8b13           mov edx, dword [ebx]
    |           0x080497e5      895004         mov dword [eax + 4], edx
    |           0x080497e8      83ec0c         sub esp, 0xc
    |           0x080497eb      ff75dc         push dword [local_24h]
    |           0x080497ee      e8cd050000     call sym.xorscura_compare
    |           0x080497f3      83c410         add esp, 0x10
    |           0x080497f6      8945d8         mov dword [local_28h], eax
    |           0x080497f9      837dd8ff       cmp dword [local_28h], 0xffffffffffffffff
    |       ,=< 0x080497fd      752d           jne 0x804982c
    |       |   0x080497ff      8b5ddc         mov ebx, dword [local_24h]
    |       |   0x08049802      e879efffff     call sym.imp.__errno_location
    |       |   0x08049807      8b00           mov eax, dword [eax]
    |       |   0x08049809      c745c8ffffff.  mov dword [local_38h], 0xffffffff
    |       |   0x08049810      8945c4         mov dword [local_3ch], eax
    |       |   0x08049813      c745c00ba704.  mov dword [local_40h], str.xorscura_compare__lx_
    |       |   0x0804981a      53             push ebx
    |       |   0x0804981b      ff75c0         push dword [local_40h]
    |       |   0x0804981e      ff75c4         push dword [local_3ch]
    |       |   0x08049821      ff75c8         push dword [local_38h]
    |       |   0x08049824      e8c7eeffff     call sym.imp.error
    |       |   0x08049829      83c410         add esp, 0x10
    |       |      ; JMP XREF from 0x080497fd (sym.check_flag_5)
    |       `-> 0x0804982c      837dd800       cmp dword [local_28h], 0
    |       ,=< 0x08049830      7507           jne 0x8049839
    |       |   0x08049832      c745e4010000.  mov dword [local_1ch], 1
    |       |      ; JMP XREF from 0x08049830 (sym.check_flag_5)
    |       `-> 0x08049839      83ec0c         sub esp, 0xc
    |           0x0804983c      ff75dc         push dword [local_24h]
    |           0x0804983f      e80c060000     call sym.xorscura_free_xod  ; void free(void *ptr)
    |           0x08049844      83c410         add esp, 0x10
    |           0x08049847      83ec0c         sub esp, 0xc
    |           0x0804984a      ff75dc         push dword [local_24h]
    |           0x0804984d      e82eeeffff     call sym.imp.free           ; void free(void *ptr)
    |           0x08049852      83c410         add esp, 0x10
    |           0x08049855      8b45e4         mov eax, dword [local_1ch]
    |           0x08049858      8d65f8         lea esp, [local_8h]
    |           0x0804985b      59             pop ecx
    |           0x0804985c      5b             pop ebx
    |           0x0804985d      5d             pop ebp
    |           0x0804985e      8d61fc         lea esp, [ecx - 4]
    \           0x08049861      c3             ret
    

Interestingly, after the prior change, not much was necessary to make flag-5 work out. Just run the program and copy out the flag. Almost.

Except that this check, it turns out, uses the comparison in xorscura_compare rather than xorscura_compare_prng, so we'll have to go back and patch that the same way.

/ (fcn) sym.xorscura_compare 117
    |   sym.xorscura_compare (int arg_14h);
    |       !   ; arg int arg_14h @ esp+0x14
    |       !      ; CALL XREF from 0x08049528 (sym.check_flag_4)
    |       !      ; CALL XREF from 0x080497ee (sym.check_flag_5)
    |       !      ; CALL XREF from 0x0804916f (sym.check_flag_3)
    |       |   0x08049dc0      55             push ebp
    |       |   0x08049dc1      57             push edi
    |       |   0x08049dc2      56             push esi
    |       |   0x08049dc3      53             push ebx
    |       |   0x08049dc4      8b442414       mov eax, dword [arg_14h]    ; [0x14:4]=1
    |       |   0x08049dc8      8b5010         mov edx, dword [eax + 0x10] ; [0x10:4]=0x30002
    |       |   0x08049dcb      85d2           test edx, edx
    |      ,==< 0x08049dcd      7411           je 0x8049de0
    |      ||   0x08049dcf      89442414       mov dword [arg_14h], eax
    |      ||   0x08049dd3      5b             pop ebx
    |      ||   0x08049dd4      5e             pop esi
    |      ||   0x08049dd5      5f             pop edi
    |      ||   0x08049dd6      5d             pop ebp
    |      |`=< 0x08049dd7      e984feffff     jmp sym.xorscura_compare_prng
           |    0x08049ddc      8d742600       lea esi, [esi]
    |      |       ; JMP XREF from 0x08049dcd (sym.xorscura_compare)
    |      `--> 0x08049de0      8b5808         mov ebx, dword [eax + 8]    ; [0x8:4]=0
    |           0x08049de3      85db           test ebx, ebx
    |       ,=< 0x08049de5      7453           je 0x8049e3a
    |       |   0x08049de7      8b28           mov ebp, dword [eax]
    |       |   0x08049de9      85ed           test ebp, ebp
    |      ,==< 0x08049deb      7e3c           jle 0x8049e29
    |      ||   0x08049ded      8b700c         mov esi, dword [eax + 0xc]  ; [0xc:4]=0
    |      ||   0x08049df0      8b7804         mov edi, dword [eax + 4]    ; [0x4:4]=0x10101
    |      ||   0x08049df3      0fb603         movzx eax, byte [ebx]
    |      ||   0x08049df6      3206           xor al, byte [esi]
    |      ||   0x08049df8      0fb617         movzx edx, byte [edi]
    |      ||   0x08049dfb      0fbec0         movsx eax, al
    |      ||   0x08049dfe      39c2           cmp edx, eax
    |     ,===< 0x08049e00      752e           jne 0x8049e30
    |     |||   0x08049e02      31c0           xor eax, eax
    |    ,====< 0x08049e04      eb1c           jmp 0x8049e22
         ||||   0x08049e06      8d7600         lea esi, [esi]
         ||||   0x08049e09      8dbc27000000.  lea edi, [edi]
    |    ||||      ; JMP XREF from 0x08049e27 (sym.xorscura_compare)
    |   .-----> 0x08049e10      0fb61403       movzx edx, byte [ebx + eax]
    |   |||||   0x08049e14      321406         xor dl, byte [esi + eax]
    |   |||||   0x08049e17      52             push edx
    |   |||||   0x08049e18      54             push esp
    |   |||||   0x08049e19      e8e2e8ffff     call sym.imp.puts           ; int puts(const char *s)
    |   |||||   0x08049e1e      5a             pop edx
    |   |||||   0x08049e1f      5a             pop edx
    |   |||||   0x08049e20      66666690       nop
    |   | |||   0x08049e24      40             inc eax
    |   | |||   0x08049e25      39e8           cmp eax, ebp
    |   `=====< 0x08049e27      75e7           jne 0x8049e10
    |     |||      ; JMP XREF from 0x08049deb (sym.xorscura_compare)
    |     |`--> 0x08049e29      31c0           xor eax, eax
    |     | |      ; JMP XREF from 0x08049e3f (sym.xorscura_compare)
    |     |.--> 0x08049e2b      5b             pop ebx
    |     |||   0x08049e2c      5e             pop esi
    |     |||   0x08049e2d      5f             pop edi
    |     |||   0x08049e2e      5d             pop ebp
    |     |||   0x08049e2f      c3             ret
    |     |!|      ; JMP XREF from 0x08049e00 (sym.xorscura_compare)
    |     `---> 0x08049e30      5b             pop ebx
    |      ||   0x08049e31      b801000000     mov eax, 1
    |      ||   0x08049e36      5e             pop esi
    |      ||   0x08049e37      5f             pop edi
    |      ||   0x08049e38      5d             pop ebp
    |      ||   0x08049e39      c3             ret
    |      !|      ; JMP XREF from 0x08049de5 (sym.xorscura_compare)
    |      |`-> 0x08049e3a      b8ffffffff     mov eax, 0xffffffff         ; -1
    \      `==< 0x08049e3f      ebea           jmp 0x8049e2b
    

There's a xor in a loop and a xor not in a loop, which is curious. It turns out the first byte of the user input vs decoded flag is tested before even entering the loop! We can patch out the jmp at 0x8049e00 and let execution fall through into the loop with eax starting at 0, which will result in the first flag byte being computed twice. This lets us only patch the loop body, which is a bit easier.

6690 @ 0x8049e00 does the trick here:

/ (fcn) sym.xorscura_compare 454
    |   sym.xorscura_compare (int arg_148h);
    |       !   ; var int local_ch @ esp+0xc
    |       !   ; var int local_14h @ esp+0x14
    |       !   ; var int local_18h @ esp+0x18
    |       !   ; var int local_1ch @ esp+0x1c
    |       !   ; var int local_1dh @ esp+0x1d
    |       !   ; var int local_1eh @ esp+0x1e
    |       !   ; var int local_1fh @ esp+0x1f
    |       !   ; var int local_20h @ esp+0x20
    |       !   ; var int local_24h @ esp+0x24
    |       !   ; arg int arg_148h @ esp+0x148
    |       !      ; CALL XREF from 0x0804916f (sym.check_flag_3)
    |       !      ; CALL XREF from 0x08049528 (sym.check_flag_4)
    |       !      ; CALL XREF from 0x080497ee (sym.check_flag_5)
    |       |   0x08049dc0      55             push ebp
    |       |   0x08049dc1      57             push edi
    |       |   0x08049dc2      56             push esi
    |       |   0x08049dc3      53             push ebx
    |       |   0x08049dc4      8b442414       mov eax, dword [local_14h]  ; [0x14:4]=1
    |       |   0x08049dc8      8b5010         mov edx, dword [eax + 0x10] ; [0x10:4]=0x30002
    |       |   0x08049dcb      85d2           test edx, edx
    |      ,==< 0x08049dcd      7411           je 0x8049de0
    |      ||   0x08049dcf      89442414       mov dword [local_14h], eax
    |      ||   0x08049dd3      5b             pop ebx
    |      ||   0x08049dd4      5e             pop esi
    |      ||   0x08049dd5      5f             pop edi
    |      ||   0x08049dd6      5d             pop ebp
    |      |`=< 0x08049dd7      e984feffff     jmp sym.xorscura_compare_prng
           |    0x08049ddc      8d742600       lea esi, [esi]
    |      |       ; JMP XREF from 0x08049dcd (sym.xorscura_compare)
    |      `--> 0x08049de0      8b5808         mov ebx, dword [eax + 8]    ; [0x8:4]=0
    |           0x08049de3      85db           test ebx, ebx
    |       ,=< 0x08049de5      7453           je 0x8049e3a
    |       |   0x08049de7      8b08           mov ecx, dword [eax]
    |       |   0x08049de9      85c9           test ecx, ecx
    |      ,==< 0x08049deb      7e3c           jle 0x8049e29
    |      ||   0x08049ded      8b700c         mov esi, dword [eax + 0xc]  ; [0xc:4]=0
    |      ||   0x08049df0      8b7804         mov edi, dword [eax + 4]    ; [0x4:4]=0x10101
    |      ||   0x08049df3      0fb603         movzx eax, byte [ebx]
    |      ||   0x08049df6      3206           xor al, byte [esi]
    |      ||   0x08049df8      0fb617         movzx edx, byte [edi]
    |      ||   0x08049dfb      0fbec0         movsx eax, al
    |      ||   0x08049dfe      39c2           cmp edx, eax
    |     ,===< 0x08049e00      752e           jne 0x8049e30
    |     |||   0x08049e02      31c0           xor eax, eax
    |    ,====< 0x08049e04      eb1c           jmp 0x8049e22
         ||||   0x08049e06      8d7600         lea esi, [esi]
         ||||   0x08049e09      8dbc27000000.  lea edi, [edi]
    |    ||||      ; JMP XREF from 0x08049e27 (sym.xorscura_compare)
    |   .-----> 0x08049e10      0fb61403       movzx edx, byte [ebx + eax]
    |   |||||   0x08049e14      0fb62c07       movzx ebp, byte [edi + eax]
    |   |||||   0x08049e18      321406         xor dl, byte [esi + eax]
    |   |||||   0x08049e1b      0fbed2         movsx edx, dl
    |   |||||   0x08049e1e      39d5           cmp ebp, edx
    |  ,======< 0x08049e20      750e           jne 0x8049e30
    |  |!||||      ; JMP XREF from 0x08049e04 (sym.xorscura_compare)
    |  ||`----> 0x08049e22      83c001         add eax, 1
    |  || |||   0x08049e25      39c8           cmp eax, ecx
    |  |`=====< 0x08049e27      75e7           jne 0x8049e10
    |  |  |||      ; JMP XREF from 0x08049deb (sym.xorscura_compare)
    |  |  |`--> 0x08049e29      31c0           xor eax, eax
    |  |  | |      ; JMP XREF from 0x08049e3f (sym.xorscura_compare)
    |  |  |.--> 0x08049e2b      5b             pop ebx
    |  |  |||   0x08049e2c      5e             pop esi
    |  |  |||   0x08049e2d      5f             pop edi
    |  |  |||   0x08049e2e      5d             pop ebp
    |  |  |||   0x08049e2f      c3             ret
    |  |  |!|      ; JMP XREF from 0x08049e00 (sym.xorscura_compare)
    |  |  |!|      ; JMP XREF from 0x08049e20 (sym.xorscura_compare)
    |  `--`---> 0x08049e30      5b             pop ebx
    |      ||   0x08049e31      b801000000     mov eax, 1
    |      ||   0x08049e36      5e             pop esi
    |      ||   0x08049e37      5f             pop edi
    |      ||   0x08049e38      5d             pop ebp
    |      ||   0x08049e39      c3             ret
    |      !|      ; JMP XREF from 0x08049de5 (sym.xorscura_compare)
    |      |`-> 0x08049e3a      b8ffffffff     mov eax, 0xffffffff         ; -1
    \      `==< 0x08049e3f      ebea           jmp 0x8049e2b
    

Looking back to the loop body, we have edx being xor'd, so that's probably where flag bytes pass through. We can get rid of movzx ebp, byte [edi + eax], movsx edx, dl, cmp ebp, edx, and jne 0x8049e30 to make space for our patch, giving 4 + 3 + 3 + 2 + 2 = 14 bytes.

ecx holds the lenth of the flag, so we still have to save that, but eax is a counter here, and the flag byte is sitting in edx. To make matters worse, ebx is also used to hold the pointer into the xor'd flag string.

Since we won't be needing the user-input string, which was in edi, we can use edi for the flag string instead, letting the ABI keep it preserved for us.

Patching 58 at 0x8049de1 to 78 changes the destination of mov ebx, dword [eax + 8] to edi, nop'ing mov edi, dword [eax + 4] at 0x08049df0 keeps edi safe, and patching 03 at 0x8049e13 to 07 changes movzx edx, byte [ebx + eax] to movzx edx, byte [edi + eax]. Now we don't have to worry about preserving ebx through puts() calls.

This means 16 bytes of patch code, in a 14 byte hole. Thankfully, we can get two more bytes by replacing add eax, 1 at 0x8049e22 with inc eax, which is just 40`. Now it's 16 bytes of code into a 16-byte hole, fitting perfectly:

3214065151505254e8e1e8ffff5a5a5859 @ 0x8049e14

and now we've patched it up to print yet another flag when run!

For this one, run without sudo, the last flag prints as gibberish because ptrace() to poke around in memory silently fails, pointing at incorrect data for the flag. sudo ./Sheb-Teth.bin, however, will print out the last flag.

+500 and we're done!

At the end you'll have a binary that looks very much like mine for this writeup

I absolutely glazed over the anti-debugging for flags 4 and 5, but that's entirely because I have no idea how to get gdb to trace properly through the forking and ptrace'ing - setting it to follow child processes simply didn't! Reading through that trickery and figuring out how it worked was quite entertaining, highly recommended as an exercise left to the reader.

PS: the binary I had in finishing the challenges was a little different. My initial attempt included me wanting to debug into a segfault I caused by patching xorscura_compare wrong (I trashed a register that shouldn't have been.. oops), so I actually looked into the ptraces and mimicked the IPC via POKEDATA with a mov. I also intially nop'd out all the ptrace and fork nonsense after that, since it was throwing GDB off the scent. That's not necessary if we just get the patching right from the first time around, perhaps after knowing what not to do..

BONUS:

I fixed up some issues in the binary after my patching, now this binary will print all of the flags when run, no longer prompting for input.

The only extra patching necessary is really to replace strncmp() calls with puts() and ensure the right parameter is passed for flags 0, 1, and 2. In xorscura_compare(), patching out comparisons as described above does the trick just fine.

Mind you, this writeup is much cleaner than the actual hacking I did at this binary during the CTF - I elided a lot of false starts and broken assembly and register fiddling.


1: When I say "patch", I do mean quite literally typing bytes into a hex editor. I personally use hexedit, but would happily accept suggestions for better terminal-based hex editors. Bless and HxD are also good, depending on your OS and preferences. Addresses like 0x804XXXX here refer to addresses in the virtual address space of the process - to convert those to addresses in the file, for this particular binary, you would subtract the base address the file expects to be loaded at. For this program it's 0x804800, which you can find through a little guesswork or looking at ELF headers with objdump -p Sheb-Teth.bin:

    Program Header:
        PHDR off    0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2
             filesz 0x00000100 memsz 0x00000100 flags r-x
      INTERP off    0x00000134 vaddr 0x08048134 paddr 0x08048134 align 2**0
             filesz 0x00000013 memsz 0x00000013 flags r--
        LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
             filesz 0x00002f68 memsz 0x00002f68 flags r-x
        LOAD off    0x00003000 vaddr 0x0804b000 paddr 0x0804b000 align 2**12
             filesz 0x000001a8 memsz 0x000001b8 flags rw-
     DYNAMIC off    0x0000300c vaddr 0x0804b00c paddr 0x0804b00c align 2**2
             filesz 0x000000e8 memsz 0x000000e8 flags rw-
        NOTE off    0x00000148 vaddr 0x08048148 paddr 0x08048148 align 2**2
             filesz 0x00000044 memsz 0x00000044 flags r--
    EH_FRAME off    0x000028d4 vaddr 0x0804a8d4 paddr 0x0804a8d4 align 2**2
             filesz 0x000000a4 memsz 0x000000a4 flags r--
       STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4
             filesz 0x00000000 memsz 0x00000000 flags rw-
        LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
    

The bolded entry here tells us that the region at file offset 0 maps to the virtual address 0x8048000, with the file and in-memory regions being the following 0x2f68 bytes. If you see a virtual address below 0x8048000 + 0x2f68, this is the mapping that applies!

In radare2, you could instead ?p <virtual_addr> to convert to a file offset, and not worry about these specifics.