This is a 200 pwn question on defcon this year. It is a 32-bit elf Program in linux. For the program, see the appendix shitsco.
I. Static Analysis
First, run the program and check the functions of the program. As shown in, this program provides an internet operating system that supports certain commands (enable, ping, and so on ).
Use the ida analysis program. main function:
The main function has three subfunctions. Analyze the three subfunctions in sequence.
The first function sub_80489d0:
It is easy to see that the content in/home/shitsco/password is read and saved to the 804c3a0 address.
The second function sub_8048c30:
This function is mainly used to read a row of user input.
The third function sub_8048a50: this function is complex, mainly to parse user input.
First, observe that the ebp is not used as a stack frame like a normal program. Here, it points to a piece of memory. This memory is exactly the system-supported command (enable ).
After analysis, we find that the block memory is a struct array that stores command information.
The struct is as follows:
Struct CommandInfo {char * command; // command name, such as enable int unknown; // No use of int Privilege; int argc; // number of parameters, for example, the command ping requires another parameter pvoid handler ;}
Privilege is the permission. If it is set to 1, the command can be executed only after the enable is successful. Memory 804c3c0 is initialized to 0. Only after enable, the memory 804c3c0 will become 1.
Handler indicates the corresponding processing function of the command.
Finally, the following command information is recorded in a table:
Command |
Privilege |
Argc |
Handler |
Enable |
0 |
1 |
Sub_8038530 |
Ping |
0 |
1 |
Sub_80493E0 |
Tracert |
0 |
1 |
Sub_8049330 |
? |
0 |
1 |
Sub_80490C0 |
Flag |
1 |
0 |
Sub_8048D40 |
Shell |
0 |
0 |
Sub_8048CF0 |
Set |
0 |
2 |
Sub_80494A0 |
Show |
0 |
1 |
Sub_8048E50 |
Credits |
0 |
0 |
Sub_8048CA0 |
Quit |
0 |
0 |
Sub_8048CD0 |
Disable |
0 |
0 |
Sub_8048CB0 |
Through the analysis of various processing functions, we found that the flag processing function directly printed the content of the flag, which indicates that the user must want to execute the flag command, but the flag command has permission restrictions, therefore, you must use the enable function.
Enable function:
The enable command must contain a parameter a1. If a1 is not empty, a1 is used as the password. If a1 is empty, the user is asked to enter the password. Then compare the entered password with the memory 804c3a0 (the password previously read by the program from the password file). If the password is the same, enable is successful.
From the above analysis, you can know that you need to know the password, but the file is on the server and there should be information leakage.
Analyze the enable processing function in detail and find that the password entered for the user in esp + 4ch-34h is shown below, and the return value of strcmp is placed in esp + 4ch-14h. If the password entered by the user is 32-bit and does not contain carriage return, the subsequent printf prints the return value of strcmp. If it is-1, the input value is too small. If it is 1, it indicates that the input is too large. If it is = 0, it means equivalent. Based on the return value of strcmp, we can guess every bit of password.
Ii. Dynamic Analysis
To perform dynamic analysis, you need to create two files in the system:/home/shitsco/flag and/home/shitsco/password, and write some bytes at will. Password ends with \ x00.
Dynamic analysis mainly verifies whether the analysis at strcmp is correct and the breakpoint is placed at 08049272.
0xbffff1e8 points to the user-Entered password 123
Run in one step to 0x08049277
Esp + 0 × 38 = 0xbffff208, the program puts the strcmp return value eax into 0xvffff208, exactly after the user input 32 bytes. The static analysis results are verified.
Iii. Write
Exp
And Test
The py script for brute force password acquisition is as follows:
Python
import socket s = socket.socket() s.connect(("127.0.0.1", 8888)) while True: d = s.recv(4096) if '$' in d: break password = ' ' * 32; for i in range(32): for j in range(33, 127): tmp = list(password) tmp[i] = chr(j) tmp = ''.join(tmp) s.send("enable \n") d = s.recv(4096) s.send(tmp + "\n") d = s.recv(4096) print d if 'Successful' in d: password = ''.join(tmp) break if chr(255) in d: print chr(j - 1) tmp = list(password) tmp[i] = chr(j - 1) password = ''.join(tmp) break s.recv(4096) print password
Exp test:
Nc port opening for listening:
Run the python script to obtain the password:
In addition, the printed password is not necessarily the password, because if the password is bruT3m3hard3rb4by, bruT3m3hard3rb4by and "bruT3m3hard3rb4by", the latter will still be considered large and not equal.
Flag is obtained successfully.
Attachment:
Http://www.2cto.com/uploadfile/2014/0610/20140610122647999.zip