Guild Hall Adventure Ch. 2 - Crackme Writeup
| Author: ker2x | Level: 2.0 | Quality: 4.0 | Platform: Unix/Linux | Language: C/C++ |
This crackme has been provided by crackmes.one.
Get it here: Link
Introduction
For all my solutions, I will use radare2: a fantastic terminal user interface reversing tool that amazes me daily on its immense potential (with a few other needed tools mixed in). So when I use a :> it is a radare2 shell command (from Visual modes you can get to this via the : key just like in vim). When I use ❱ it is referring to a normal shell command. With that out of the way let's get to the meat of this crackme!
Part One
So this is the second part of the crackme story line that ker2x has made. Let's see how the story builds!
Lets open this binary and see what it does without any arguments or anything:
❱ ./adventure2
Oooooooooo ! Socially approriate greetings !
Welcome to chapter 2 !
--------------------------------------------
This one is a bit more complex but still 'Easy'
In order to keep it at this level i'll provide just
a bit of help.
Each step will be in a self contained function.
I may have a few helper functions here and there
but nothing big. I hate difficult easy challenge
as much as you do.
The first step is in this main function.
If you completed the previous chapter, this 1st step should be easy to guess =^_^=
Once you completed this main step, you can directly skil to step2 using './adventure2 2'... probably :D
You can (try to) cheat and skip the main step entirely but what's the point then ?
Good luck ! <3
--
ker2x
:wq
(Press enter to continue)
Well here is a nice little readme from the author. Catch the :wq at the end! I guess we have another vim user here! Okay, so what I got out of that is that the main function holds all of part one, then part two is in a helper function. Also, we are told that there is an argument that allows us to go to the next step to skip all the inputs in this one.
Press enter and continue:
* Previously in Chapter 1 :
---------------------------
- After being summoned from another world, you went to the guild hall
- You met the security guard and didn't die
- You entered the guild hall and didn't die
- Then you reached the registration office
and maybe died a few times. But you're a hero
from another world so it's fine =^_^=
* Chapter 2, the registration office.
-------------------------------------
* The receptionist notice you coming directly to her :
"Heeeelp ! KILL ! KILL ! KILL !"
(-0HP)
(Press enter to continue)
Lets try hitting enter again… well that didn't work.
(- 1000HP)
Segmentation fault
By the way, I had to switch to bash (instead of zsh) to get the right output for the segfault, for some reason zsh really didn't like it and crashes, atleast on my end.
Seems we need a different input here instead of enter, maybe that is what ker2x was talkin about with “misguiding” in the README.txt he gave us. I tried an ltrace but this didn't help or even give any pointers other than that this binary is using getchar to take input. Let's open this up in radare2 and take a look: Scrolling past all the excess strings and puts/printf's etc, getting to the part we need to look at, there is some manipulation after that second getchar:
0x55e90be00af8 lea rdi, str._Heeeelp___KILL___KILL___KILL____n__0HP__n ; 0x55e90be01620 ; "\"Heeeelp ! KILL ! KILL ! KILL !\"\n(-0HP)\n" ; const char *s
0x55e90be00aff call sym.imp.puts ; int puts(const char *s)
0x55e90be00b04 lea rdi, str._Press_enter_to_continue_ ; 0x55e90be013ff ; "(Press enter to continue)" ; const char *s
0x55e90be00b0b call sym.imp.puts ; int puts(const char *s)
0x55e90be00b10 call sym.imp.getchar ; int getchar(void)
0x55e90be00b15 mov dword [rbp - 0xb4], eax
0x55e90be00b1b mov rax, qword [rbp - 0xb0]
0x55e90be00b22 movzx eax, byte [rax]
0x55e90be00b25 movsx eax, al
0x55e90be00b28 add eax, 1
0x55e90be00b2b cmp dword [rbp - 0xb4], eax
0x55e90be00b31 b je 0x55e90be00b58
As you can see by the b I set a breakpoint at 0x55e90be00b31 and will use dc to get to it (dc: debug continue - continues program till breakpoint). After continuing to this breakpoint, lets read where we need to check. So we see in the cmp (line 0x55e90be00b2b) that the variable rbp-0xb4 (which is var_b4h defined above) gets compared with eax (which we can check):
:> ? eax ~string,hex
hex 0x48
string "H"
Interesting, it is 'H' after the manipulation. Remember how to see our variables? Yep, afvd! Let's check var_b4h and see if our input gets manipulated too.
:> afvd~var_b4h
var var_b4h = 0x7ffc3983f71c = 10
If you noticed the `~` in my commands, this is the built in `GREP` in radare2 believe it or not, in the example above `? eax ~string,hex` the comma is an OR, so it greps for "string" or "hex".
Okay! So our input does not get manipulated which makes this very easy. If you noticed the 10 (0x0a) there, that is the ASCII value for LF (Line Feed) which is essentially like a newline, and that is what should be expected since we gave the input a newline (Enter Key). Let's try using an H instead of enter there:
❱ ./adventure2
(Press enter to continue)
H
"Wait !"
Check that out! It worked! Now we have to do the same thing 4 more times haha! Let's look at the next block and set a breakpoint at 0x5585b5600bae and continue to it with dc (Press any key to test when prompted).
0x5585b5600b58 lea rdi, str._Wait___ ; 0x5585b5601654 ; "\"Wait !\"" ; const char *s
0x5585b5600b5f call sym.imp.puts ; int puts(const char *s)
0x5585b5600b64 add qword [rbp - 0xb0], 1
0x5585b5600b6c call sym.imp.getchar ; int getchar(void)
0x5585b5600b71 mov dword [rbp - 0xb4], eax
0x5585b5600b77 call sym.imp.getchar ; int getchar(void)
0x5585b5600b7c mov dword [rbp - 0xb4], eax
0x5585b5600b82 mov rax, qword [rbp - 0xb0]
; DATA XREF from sym.step2 @ 0x5585b5600e29
0x5585b5600b89 add rax, 1
0x5585b5600b8d mov qword [rbp - 0x98], rax
0x5585b5600b94 mov rax, qword [rbp - 0x98]
0x5585b5600b9b sub rax, 1
0x5585b5600b9f movzx eax, byte [rax]
0x5585b5600ba2 movsx eax, al
0x5585b5600ba5 add eax, 1
0x5585b5600ba8 cmp dword [rbp - 0xb4], eax
;-- rip:
0x5585b5600bae b je 0x5585b5600bd5
Again eax is being compared with var_b4h (our input). Now that we hit the breakpoint we can check what eax is:
:> ? eax ~string,hex
hex 0x65
string "e"
Well this is obviously spelling out a word, let's try e after doing H in a separate instance:
❱ ./adventure2
...
(Press enter to continue)
H
"Wait !"
e
- It's trying to say something ...
- it's a he ? Kawaiiii~~~~ =^_^=
(- 3000HP)
Segmentation fault
Okay, I think you guys can figure the rest out on your own for the next 3 letters, either the debugging route, or just guessing…
Tip
To restart debugging in radare2, you can use the ood or doo commands to “re-open for debugging” essentially. These can also take flags as arguments, e.g: ood test would re-open the program passing in the test argument.
Solution
I hope you could find the next three letters on your own but this wouldn't be a valid solution without having them here. Try doing it on your own though and see if you can get the same ones I did!
(Press enter to continue)
H
"Wait !"
e
- It's trying to say something ...
- it's a he ? Kawaiiii~~~~ =^_^=
l
"Yes ! you can do it !!"
l
- huh ? you come from the deep underground ?
- Should we report it to the church ? Followers of Hades are punished by the holy church ... or so i'm told
- Not that we're followers, we're the free guild... free as in free beer ! Or
was it free speech ?
- Mmmm... what do we do ? what do we do ?
o
"Oooooooooo ! Socially approriate greetings !
"So you're not a monster after all ! Sorry sorry !"
(Press enter to continue... probably...)
Yep it is Hello! The little story lines to go along with it as you figure out the letters is pretty hilarious, not gonna lie lol!
After that hit enter two times (read the dissassembly, there are no checks for those) and you are now on the second step!!
Part Two
So remember earlier we were told that the first step all happens really in the main function? Well now we are in sym.step2 function so on to step 2!
Getting the Shortcut Key
First, there is a little part in the beginning of dissassembly that checks for a valid argument. If you get it completely wrong:
❱ ./adventure2 test
NOPE!
Segmentation fault
The logic is a little tricky so I provided some pictures of the flow to clear it up:


As you can see, argc gets checked at the end of the first block. If it is not 1 then we continue to the left, else it will continue down to step 1 essentially. Okay, that is easy, lets just give it an argument: that will make argc = 2. If we set a breakpoint at 0x55d6310008fb, you will see that this works. This breakpoint will help for the second block here as well, so follow along. There is a lot of manipulation in this second block so lets just check the variables by debugging at the breakpoint we set: (I'm using ood 2 as the argument because remember the hint when initially opening of the binary ;))
:> ood 2
:> dc
hit breakpoint at: 0x558893a008fb
:> pdb
0x558893a008c2 mov rax, qword [rbp - 0xd0]
0x558893a008c9 add rax, 8
0x558893a008cd mov rax, qword [rax]
0x558893a008d0 add rax, 1
0x558893a008d4 mov rdi, rax ; const char *s
0x558893a008d7 call sym.imp.strlen ; size_t strlen(const char *s)
0x558893a008dc mov rdx, rax
0x558893a008df mov rax, qword [rbp - 0xd0]
0x558893a008e6 add rax, 8
0x558893a008ea mov rax, qword [rax]
0x558893a008ed movzx eax, byte [rax]
0x558893a008f0 movsx eax, al
0x558893a008f3 sub eax, 0x30 ; 48
0x558893a008f6 cdqe
0x558893a008f8 cmp rdx, rax
;-- rip:
0x558893a008fb b je 0x558893a00909
:> dr ~rax,rdx
rax = 0x00000002
rdx = 0x00000000
So check it out, there is a strlen that throws the length of our passed in arg to rdx which gets compared at the end of the block with our rax. So since our eax is 2 and our rdx is 0, lets try to make rdx 3 characters instead.
:> ood 200
:> dc
...
Hit step2? Good, it should have worked. Anything that starts with a too, is 3 characters (even letters work), and not 222 will work to skip to step2!
Step 2
Let's start playing with step2 now! Remember it is in a different function, so in radare2 if you want to seek to it use: s sym.step2 or just to view it: pdf @ sym.step2 | VV @ sym.step2.
❱ ./adventure2 200
Welcome to step 2 of chapter 2 !
If you see this message because you randomly played with arguments
but didn't complete the 1st step, please go back and run the program without arguments
Unless you're cheating ? meh... whatever...
BUT !! If you completed the 1st step : CONGRATULATION \o/ !!
...
Damn... I painstakingly coded this whole [go directly to step 2 stuff]
So now i guess i really have to code a step 2
Don't want to do it... (Just press enter or something and we'll improvise somehow)
(pressed enter)
By the way, what argument did you use to come here ? 2
2 ? good good... please remember it !
(Press enter or whatever, who care ?)
So at this point we get more dialog, we successfully got to step 2 without cheating! Can safely hit enter the first time, for the second input it is just a getchar so it will only take one character but it doesn't matter too much, it will overflow to the other inputs though if you give it too much. Hit enter again after you put a number in:
- So you want to register to the guild ? Math question then !
- it's totally not because i'm lazy or anything ! Bakkaaaa~ !
what's 2 + 3 * 5 ?
Oh we get a math question! Looks easy enough! 17 should be the right answer here unless im just stupid lol…
BWAHAHAHAHA BAKAAAAAAAA !!! 0x44ab8d14 is super totally wrooong !
Segmentation fault (core dumped)
...
Segmentation fault
Am I that stupid, he is calling be a BAKA (idiot in Japanese lol)? No haha obviously not, that math question isn't real and is just to throw us off from the disassembly. Let's set a breakpoint at 0x561b3d400f17 (the jump line after the compare) and see what the values being compared are:
:> db 0x561b3d400f17
:> dc
- So you want to register to the guild ? Math question then !
- it's totally not because i'm lazy or anything ! Bakkaaaa~ !
what's 2 + 3 * 5 ? 17
hit breakpoint at: 0x561b3d400f17
:> pdb ~cmp,je
│ 0x561b3d400f14 3945ec cmp dword [rbp - 0x14], eax
│ ╭─< 0x561b3d400f17 b 7445 je 0x561b3d400f5e
Now, I wouldn't have caught this so easily my first time through without my handy dandy visual panel layout in radare2. You can do anything with this panel mode and nothing makes me happier than something that lets me make it my own. This made it super simple and efficient for me to check the variables and everything else.

Take a look at var_14h though! That is what is being compared with our input… 65. Let's try it!
what's 2 + 3 * 5 ? 65
BWAHAHAHAHA BAKAAAAAAAA !!! 0xedea1884 is super totally wrooong !
Segmentation fault (core dumped)
...
ho damn, that's right...
WHY ?
To be continued... (you really succeded but i'll kill you anyway. don't worry, you'll be fine)
Segmentation fault
Would you look at that! We beat step two! The first “Segmentation fault (core dumped)” is actually a made-up function that prints that to throw us off, the second Segfault though is on purpose and is a real segfault that happens due to calling rdx I believe. It seems that rdx may hold a function pointer that isn't allocated or something of the sort, but don't quote me on it! Either way it was a pretty cool way to misguide the challenger. Didn't stump us though!
Recap
Step 1
We first are prompted with a readme and to hit enter. Hit it once, but after that we had to figure out the right input. Remember what it was? Yep! Hello one letter at a time which got us to step 2 (after 2 more enters).
Step 2
First, we cracked the shortcut key to skip step1 to test more efficiently in step2. The key is anything that starts with a 2 and is 3 characters long, 200 works perfect.
Rerun the binary with 200 or the key you want as an argument.
Next, when prompted we hit enter, then put in a number that we used to get to step 2. Just throw 2 in there, it doesn't matter much and hit enter. We then are prompted with a math question that is just to misguide so we dug into the disassembly and look closely at the compare which is comparing our input to 65. Try that for the input and we are golden after a few more enter presses!
Closing
Hope you enjoyed this writeup! This one was pretty long, atleast this blog post is. Can just skip to recap to get past all the explanation and right to the solution.
This second part of the Guild Hall Adventure story has been a blast though! Really odd not going to lie but still has been fun! Hope you guys enjoyed it like I did!
Thanks for reading and have a blessed day! Shado out.