Tags: reversing
Rating:
# 2020 Defenit CTF - MoM's Touch
>###### TAGS: `reversing`
>[name=rlaclgjs@PLUS]
## Attachments
* writeup
* [solver code](https://gist.github.com/rlaclgjs1107/d3f748657494ee286948888fd753f03f#file-sol-py)
Attachments are uploaded on [gist](https://gist.github.com/rlaclgjs1107/d3f748657494ee286948888fd753f03f)
## Challenge
Challenge provides an `ELF` file named `momsTouch`.
When I opened `momsTouch` with IDA, I noticed that this is a basic reversing challenge for analyzing the flag-checking program. So, let's check out how this program check our input!
## Analysis
```C
int __cdecl main()
{
char *buf; // eax
char *s; // esi
ssize_t v2; // eax
sub_80486B0();
puts("Mom Give Me The FLAG!");
buf = (char *)malloc(0x64u);
s = buf;
if ( !buf )
{
perror("[*]Error : malloc()");
goto LABEL_12;
}
v2 = read(0, buf, 0x64u);
if ( v2 < 0 )
{
perror("[*]Error : read()");
LABEL_12:
exit(-1);
}
if ( s[v2 - 1] == 10 )
s[v2 - 1] = 0;
if ( strlen(s) != 73 )
{
puts("Mom, Check the legnth..");
exit(0);
}
if ( (unsigned __int8)sub_80487A0((int)s) )
puts("Correct! Mom! Input is FLAG!");
else
puts("Try Again..");
free(s);
return 0;
}
```
This is the `main` function we have. In this function, we can figure out some meaningful information.
1. The flag length is 73.
2. This program verify our input in a function `sub_80487a0`.
```C {.line-numbers}
int __cdecl sub_80487A0(int a1)
{
signed int v1; // esi
int v2; // ebp
int v3; // eax
int result; // eax
v1 = 0;
while ( 1 )
{
v2 = (unsigned __int8)(16 * LOBYTE(dword_80492AC[v1]) | ((unsigned int)dword_80492AC[v1] >> 4));
v3 = rand();
if ( (dword_80492AC[(unsigned __int8)(4 * (v3 + v3 / 255) | ((unsigned int)(v3 % 255) >> 2))] ^ dword_80492AC[v2] ^ *(char *)(a1 + v1)) != dword_8049144[v1] )
break;
++v1;
LOBYTE(result) = 1;
if ( v1 > 72 )
return (unsigned __int8)result;
}
LOBYTE(result) = 0;
return (unsigned __int8)result;
}
```
So, this is the function `sub_80487A0`. This function uses random number(not actually "real" random because we can find a seed in other function), complex conditional expression to check our input.
However, Let's see `v1`. `v1` is increasing for each loop, unless we fail to pass the conditional expression just above. Then, if `v1` is over 72, the function returns `1` that means 'true'. Since we know 73 is the length of the flag, I guessed that this function checks our flag character by character.
If we can see whether the program enters `++v1;` part or not, we can brute force the flag by 1 printable character.
## Solution
So, I write gdb script on python to automate brute forcing process.
Here is my solution.
```python
import gdb
import string
class BP_Manager(gdb.Breakpoint):
def stop(self):
global count
count += 1
return False
gdb.execute('file momsTouch')
bp = BP_Manager("*0x0804881c")
trial = "_"*73
count = 0
trial_pos = 0
while trial_pos < 73:
for ch in string.printable:
if ch in ['\"', '`', '\'','$', '&','(', ')', '>', '<', '|', ';', '\\']:
continue
trial = trial[:trial_pos] + ch + trial[trial_pos+1:]
trial_file = open("trial", "w")
print(trial, file=trial_file)
print("Trying '%s'..."%trial)
trial_file.close()
gdb.execute("r < trial")
print("count : %d"%count)
print("trial_pos : %d"%trial_pos)
if count == trial_pos+1:
trial_pos += 1
count = 0
break
else:
print("Wrong...")
count = 0
print(trial)
```
After waiting some time, we can get the flag!
```
Correct! Mom! Input is FLAG!
[Inferior 1 (process 30928) exited normally]
Warning: not running
count : 73
trial_pos : 72
Defenit{ea40d42bfaf7d1f599abf284a35c535c607ccadbff38f7c39d6d57e238c4425e}
```
## Flag
`Defenit{ea40d42bfaf7d1f599abf284a35c535c607ccadbff38f7c39d6d57e238c4425e}`