The challenge description was: We got a little lazy so we just tweaked an old one a bit

Unfortunately I didn't participated in earlier CSAW CTF so I'm not sure what they meant by that, but looking at the binary file name it was apparently a challenge from CSAW 2013 they modified.

Let's download it and see what is going on when we run it:

Well, that's cute. Not much to do from there. After opening the binary with Ollydbg I noticed a couple anti-debugging calls such as INT 3 and IsDebuggerPresent.

0040108C     FF15 14604000  CALL DWORD PTR DS:[<&KERNEL32.IsDebugger>;  kernel32.IsDebuggerPresent
00401092   . 85C0           TEST EAX,EAX
00401094   . 74 23          JE SHORT csaw2013.004010B9
00401096   > 41             INC ECX
00401097   . 41             INC ECX
00401098   . 41             INC ECX
00401099   . 41             INC ECX
0040109A     CC             INT3
0040109B   . 8B55 F4        MOV EDX,DWORD PTR SS:[EBP-C]
0040109E   . E8 5DFFFFFF    CALL csaw2013.00401000

Since IsDebuggerPresent returns false when there is no debugger detected, let's just NOP both of these calls we don't need them anyway.

0040108C     90             NOP
0040108D     90             NOP
0040108E     90             NOP
0040108F     90             NOP
00401090     90             NOP
00401091     90             NOP
00401092   . 85C0           TEST EAX,EAX
00401094   . 74 23          JE SHORT csaw2013.004010B9
00401096   > 41             INC ECX
00401097   . 41             INC ECX
00401098   . 41             INC ECX
00401099   . 41             INC ECX
0040109A     90             NOP
0040109B   . 8B55 F4        MOV EDX,DWORD PTR SS:[EBP-C]
0040109E   . E8 5DFFFFFF    CALL csaw2013.00401000

Now I'm really curious to know what is the method just after the call to INT 3 is doing exactly. If there is a call to trap any debugger before it maybe it's something important:

00401000  /$ 56             PUSH ESI
00401001  |. 8B35 389B4000  MOV ESI,DWORD PTR DS:[409B38]
00401007  |. 8D42 01        LEA EAX,DWORD PTR DS:[EDX+1]
0040100A  |. 57             PUSH EDI
0040100B  |. 8D78 01        LEA EDI,DWORD PTR DS:[EAX+1]
0040100E  |> 8A08           /MOV CL,BYTE PTR DS:[EAX]
00401010  |. 40             |INC EAX
00401011  |. 84C9           |TEST CL,CL
00401013  |.^75 F9          \JNZ SHORT csaw2013.0040100E
00401015  |. 2BC7           SUB EAX,EDI
00401017  |. C1E8 02        SHR EAX,2
0040101A  |. 33C9           XOR ECX,ECX
0040101C  |. 40             INC EAX
0040101D  |. 74 08          JE SHORT csaw2013.00401027
0040101F  |> 31348A         /XOR DWORD PTR DS:[EDX+ECX*4],ESI
00401022  |. 41             |INC ECX
00401023  |. 3BC8           |CMP ECX,EAX
00401025  |.^72 F8          \JB SHORT csaw2013.0040101F
00401027  |> 5F             POP EDI                                  ;  ntdll.7C910208
00401028  |. 5E             POP ESI
00401029  \. C3             RETN

Looks like there are two loops in this method, one to get some bytes and another to XOR them. Let's just put a breakpoint on 0x00401027 and see if there is anything interesting in memory.

Stack [0012FF58]=7C910208 (ntdll.7C910208)
EDI=00381EA2, (ASCII "lag{reversing_is_not_that_hard!}")
Jump from 0040101D

00381EA2  6C 61 67 7B 72 65 76 65  lag{reve
00381EAA  72 73 69 6E 67 5F 69 73  rsing_is
00381EB2  5F 6E 6F 74 5F 74 68 61  _not_tha
00381EBA  74 5F 68 61 72 64 21 7D  t_hard!}

We got our flag: reversing_is_not_that_hard!