-
Notifications
You must be signed in to change notification settings - Fork 181
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
66 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,18 +4,19 @@ | |
`graftcp` is a proxy tool inspiring by [maybe](https://github.com/p-e-w/maybe) and [proxychains](https://github.com/haad/proxychains). | ||
It hooks `connect(2)` function via `ptrace(2)` and redirects the connection through SOCKS5 proxies. | ||
--> | ||
|
||
# graftcp | ||
|
||
**English** | [简体中文](./README.zh-CN.md) | ||
|
||
## Introduction | ||
## Introduction | ||
|
||
`graftcp` can redirect the TCP connection made by the given program \[application, script, shell, etc.\] to SOCKS5 or HTTP proxy. | ||
|
||
Compared with [tsocks](https://linux.die.net/man/8/tsocks), [proxychains](http://proxychains.sourceforge.net/) or [proxychains-ng](https://github.com/rofl0r/proxychains-ng), `graftcp` is not using the [LD_PRELOAD trick](https://stackoverflow.com/questions/426230/what-is-the-ld-preload-trick) which only work for dynamically linked programs, e.g., [applications built by Go can not be hook by proxychains-ng](https://github.com/rofl0r/proxychains-ng/issues/199). `graftcp` can trace or modify any | ||
given program's connect by [`ptrace(2)`](https://en.wikipedia.org/wiki/Ptrace), so it is workable for any program. The principle will be explained in this paragraph of [how does it work](#principles). | ||
|
||
## Installation | ||
## Installation | ||
|
||
### Install from source | ||
|
||
|
@@ -26,6 +27,7 @@ git clone https://github.com/hmgle/graftcp.git | |
cd graftcp | ||
make | ||
``` | ||
|
||
After make finishes, you'll be able to use `local/graftcp-local` and `./graftcp`. | ||
Optionally, you can also install them to system: | ||
|
||
|
@@ -95,13 +97,15 @@ Options: | |
-n --not-ignore-local | ||
Connecting to local is not changed by default, this | ||
option will redirect it to SOCKS5 | ||
-u --user=<username> | ||
Run command as USERNAME handling setuid and/or setgid | ||
-V --version | ||
Show version | ||
-h --help | ||
Display this help and exit | ||
``` | ||
|
||
`mgraftcp`: Combined `graftcp-local` and `graftcp` (`mgraftcp` = `graftcp-local` + `graftcp`). | ||
`mgraftcp`: Combined `graftcp-local` and `graftcp` (`mgraftcp` = `graftcp-local` + `graftcp`). | ||
`mgraftcp` can be used to replace `graftcp` without running `graftcp-local`. | ||
|
||
```console | ||
|
@@ -126,6 +130,8 @@ Usage: mgraftcp [-hn] [-b value] [--enable-debug-log] [--http_proxy value] [--se | |
SOCKS5 password | ||
--socks5_username=value | ||
SOCKS5 username | ||
-u, --username=value | ||
Run command as USERNAME handling setuid and/or setgid | ||
--version Print the mgraftcp version information | ||
-w, --whiteip-file=value | ||
Only redirect the connect that destination IP/CIDR in the | ||
|
@@ -167,9 +173,11 @@ Launch `Bash` / `Zsh` / `Fish` via `graftcp`, then all the TCP traffic generated | |
% ./graftcp bash | ||
$ wget https://www.google.com | ||
``` | ||
|
||
![demo](demo.gif) | ||
|
||
<a id="principles"></a> | ||
|
||
## How does it work? | ||
|
||
To achieve the goal of redirecting the TCP connection of a app to another destination address and the app itself is not aware of it, these conditions are probably required: | ||
|
@@ -178,7 +186,7 @@ To achieve the goal of redirecting the TCP connection of a app to another destin | |
- Modify the destination address argument of `connect(2)` to `graftcp-local`'s address, and restart the stopped syscall. After the syscall returns successfully, the app thought it has connected the original destination address, but in fact it is connected to the `graftcp-local`, so we named it "graft". | ||
- `graftcp-local` establish a SOCKS5 connection based on the information of app's original destination address, then redirect the requests from the app to the SOCKS5 proxy. | ||
|
||
Someone may have a question here: since we can modify the arguments of a syscall, modify the app's `write(2)` / `send(2)` buf argument, attach the original destination information to the `write` buffer, isn't it simpler? The answer is that cannot be done. Because attach data to the buffer of the tracked child process, it may case a buffer overflow, causing crash or overwrite other data. | ||
Someone may have a question here: since we can modify the arguments of a syscall, modify the app's `write(2)` / `send(2)` buf argument, attach the original destination information to the `write` buffer, isn't it simpler? The answer is that cannot be done. Because attach data to the buffer of the tracked child process, it may case a buffer overflow, causing crash or overwrite other data. | ||
In addition, as the [`execve(2)` will detach and unmap all shared memory](http://man7.org/linux/man-pages/man2/execve.2.html), we also cannot add extra data to the `write` buffer of traced app by sharing memory, so we send the original destination address via `pipe`. | ||
|
||
The simple sketch is as follows: | ||
|
@@ -220,10 +228,30 @@ programs selection way: this way can only perform redirection for specified prog | |
|
||
No. By default, `graftcp` ignore the connections to localhost. If you want to redirect all addresses, you can use the `-n` option. If you want to ignore more addresses, you can add them to the blacklist IP file; if you want to redirect only certain IP addresses, you can add them to the whitelist IP file. Use `graftcp --help` to get more information. | ||
|
||
### I am suffering a DNS cache poisoning attack, does `graftcp` handle DNS requests? | ||
### I am suffering a DNS cache poisoning attack, does `graftcp` handle DNS requests? | ||
|
||
No. `graftcp` currently only handles TCP connections. [`dnscrypt-proxy`](https://github.com/jedisct1/dnscrypt-proxy) or `ChinaDNS` may help you. | ||
|
||
### Running `[m]graftcp yay` or `graftcp sudo ...` results in an error and exit, how to solve this? | ||
|
||
The `yay` command on Arch Linux actually invokes `sudo pacman ...`, which requires the tracer to have root privileges to obtain permissions to trace the child process. You can start `[m]graftcp` with `sudo` and specify the current user to run the subsequent command: `sudo [m]graftcp sudo -u $USER yay`, or `sudo [m]graftcp -u $USER sudo ...`. | ||
|
||
If you find the above command too long, you can copy a `[m]graftcp` binary with the setuid bit set and create a wrapper script to simplify the input: | ||
|
||
```sh | ||
cp mgraftcp _sumgraftcp | ||
sudo chown root _sumgraftcp | ||
sudo u+s _sumgraftcp | ||
cat << 'EOF' > sumg | ||
#!/bin/sh | ||
./_sumgraftcp -u "$USER" "$@" | ||
EOF | ||
chmod +x sumg | ||
# sumg yay | ||
# sumg sudo ... | ||
``` | ||
|
||
### The `clone(2)`'s argument has a flag `CLONE_UNTRACED` to avoid being traced, how does `graftcp` do forced tracing? | ||
|
||
`graftcp` will intercept the `clone(2)` syscall, and clearing the `CLONE_UNTRACED` flag, so the tracked child process could not escape the fate of being tracked. In addition, this `CLONE_UNTRACED` flag is intended for the kernel, and user space program should not set it. | ||
|
@@ -238,6 +266,7 @@ No. macOS's [`ptrace(2)`](http://polarhome.com/service/man/?qf=ptrace&af=0&sf=0& | |
|
||
- [x] ARM/Linux Support | ||
- [x] i386/Linux Support | ||
- [ ] UDP Support | ||
|
||
## Acknowledgements and References | ||
|
||
|
@@ -249,6 +278,6 @@ No. macOS's [`ptrace(2)`](http://polarhome.com/service/man/?qf=ptrace&af=0&sf=0& | |
|
||
## LICENSE | ||
|
||
Copyright © 2016, 2018-2021 Hmgle <[email protected]> | ||
Copyright © 2016, 2018-2024 Hmgle <[email protected]> | ||
|
||
Released under the terms of the [GNU General Public License, version 3](https://www.gnu.org/licenses/gpl-3.0.html) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -89,6 +89,8 @@ Options: | |
-n --not-ignore-local | ||
Connecting to local is not changed by default, this | ||
option will redirect it to SOCKS5 | ||
-u --user=<username> | ||
Run command as USERNAME handling setuid and/or setgid | ||
-V --version | ||
Show version | ||
-h --help | ||
|
@@ -119,6 +121,8 @@ Usage: mgraftcp [-hn] [-b value] [--enable-debug-log] [--http_proxy value] [--se | |
SOCKS5 password | ||
--socks5_username=value | ||
SOCKS5 username | ||
-u, --username=value | ||
Run command as USERNAME handling setuid and/or setgid | ||
--version Print the mgraftcp version information | ||
-w, --whiteip-file=value | ||
Only redirect the connect that destination IP/CIDR in the | ||
|
@@ -164,6 +168,7 @@ $ wget https://www.google.com | |
![demo](demo.gif) | ||
|
||
<a id="principles"></a> | ||
|
||
## 工作原理 | ||
|
||
要达到重定向一个 app 发起的的 TCP 连接到其他目标地址并且该 app 本身对此毫无感知的目的,大概需要这些条件: | ||
|
@@ -172,7 +177,7 @@ $ wget https://www.google.com | |
- 修改这次 `connect(2)` 系统调用的目标地址参数为 `graftcp-local` 的地址,然后恢复执行被中断的系统调用。返回成功后,这个程序以为自己连的是原始的地址,但其实连的是 `graftcp-local` 的地址。这个就叫“移花接木”。 | ||
- `graftcp-local` 根据连接信息和目标地址信息,与 SOCKS5 proxy 建立连接,把 app 的请求的数据重定向到 SOCKS5 proxy。 | ||
|
||
这里可能有个疑问:既然可以修改任何系统调用的参数,那么通过修改 app 的 `write(2)` / `send(2)` 的参数,直接往 `buffer` 里面附加原始目标地址信息给 `graftcp-local` 不是更简单吗?答案是这无法做到。如果直接往运行在子进程的被跟踪程序的 `buffer` 添加信息,可能会造成缓冲区溢出,造成程序崩溃或者覆盖了其他数据。 | ||
这里可能有个疑问:既然可以修改任何系统调用的参数,那么通过修改 app 的 `write(2)` / `send(2)` 的参数,直接往 `buffer` 里面附加原始目标地址信息给 `graftcp-local` 不是更简单吗?答案是这无法做到。如果直接往运行在子进程的被跟踪程序的 `buffer` 添加信息,可能会造成缓冲区溢出,造成程序崩溃或者覆盖了其他数据。 | ||
另外,[`execve(2)` 会分离所有的共享内存](http://man7.org/linux/man-pages/man2/execve.2.html),所以也不能通过共享内存的方式让被跟踪的 app 的 `write` buffer 携带更多的数据,因此这里采用管道方式给 `graftcp-local` 传递原始的目标地址信息。 | ||
|
||
简单的流程如下: | ||
|
@@ -205,7 +210,7 @@ $ wget https://www.google.com | |
|
||
全局式:比如使用 `iptables` + `RedSocks` 可以把系统符合一定规则的流量转换为 SOCKS5 流量。这种方式的优点是全局有效;缺点是所有满足该规则的流量都被重定向了,影响范围较大。 | ||
|
||
设置环境变量方式:一些程序启动时会读取 proxy 相关的环境变量来决定是否将自己的数据转换为对应代理协议的流量,比如 `curl` 会[读取 `http_proxy`, `ftp_proxy`, `all_proxy` 环境变量并根据请求 scheme 来决定转换为哪种代理流量](https://curl.haxx.se/libcurl/c/CURLOPT_PROXY.html)。这种方法只有程序本身实现了转换的功能才有效,局限性较大。 | ||
设置环境变量方式:一些程序启动时会读取 proxy 相关的环境变量来决定是否将自己的数据转换为对应代理协议的流量,比如 `curl` 会[读取 `http_proxy`, `ftp_proxy`, `all_proxy` 环境变量并根据请求 scheme 来决定转换为哪种代理流量](https://curl.haxx.se/libcurl/c/CURLOPT_PROXY.html)。这种方法只有程序本身实现了转换的功能才有效,局限性较大。 | ||
|
||
仅针对程序方式: 这种方式可以仅针对特定的程序执行重定向,比如 `tsocks` 或 `proxychains`。如前面提到,它们之前都是使用 `LD_PRELOAD` 劫持动态库方式实现,对 `Go` 之类默认静态链接编译的程序就无效了。`graftcp` 改进了这一点,能够重定向任何程序的 TCP 连接。 | ||
|
||
|
@@ -217,6 +222,25 @@ $ wget https://www.google.com | |
|
||
不会。`graftcp` 目前仅处理 TCP 连接。建议使用 `dnscrypt-proxy` 或 `ChinaDNS` 等方式解决 DNS 污染问题。 | ||
|
||
### 运行 `[m]graftcp yay` 或者 `graftcp sudo ...` 报错并退出,该如何解决? | ||
|
||
Arch Linux 的 `yay` 实际也会调用 `sudo pacman ...`,这需要 tracer 具备 root 特权才能获取到跟踪子进程的权限。可以用 sudo 来启动 `[m]graftcp`,并指定当前用户运行后续命令:`sudo [m]graftcp sudo -u $USER yay`,或者 `sudo [m]graftcp -u $USER sudo ...`。 | ||
如何觉得上面命令太长,可以复制一个带 setuid 位的 [m]graftcp 副本,并写一个包裹脚本来简化输入: | ||
|
||
```sh | ||
cp mgraftcp _sumgraftcp | ||
sudo chown root _sumgraftcp | ||
sudo u+s _sumgraftcp | ||
cat << 'EOF' > sumg | ||
#!/bin/sh | ||
./_sumgraftcp -u "$USER" "$@" | ||
EOF | ||
chmod +x sumg | ||
# sumg yay | ||
# sumg sudo ... | ||
``` | ||
|
||
### `clone(2)` 参数有个叫 `CLONE_UNTRACED` 的标志位,可以避免让父进程跟踪到自己,`graftcp` 是如何做到强制跟踪的? | ||
|
||
`graftcp` 在子进程调用 `clone(2)` 之前会把它拦截,清除这个 `CLONE_UNTRACED` 标志位,所以被跟踪的子进程最终还是难逃被跟踪的命运。另外,这个 `CLONE_UNTRACED` 标志位本意是给内核使用的,普通程序不应该去设置它。 | ||
|
@@ -231,6 +255,7 @@ Linux 提供了一种限制被 `ptrace(2)` 跟踪的方法:设置 [`/proc/sys/ | |
|
||
- [x] ARM/Linux 支持 | ||
- [x] i386/Linux 支持 | ||
- [ ] UDP 支持 | ||
|
||
## 感谢及参考 | ||
|
||
|
@@ -242,6 +267,6 @@ Linux 提供了一种限制被 `ptrace(2)` 跟踪的方法:设置 [`/proc/sys/ | |
|
||
## License | ||
|
||
Copyright © 2016, 2018-2021 Hmgle <[email protected]> | ||
Copyright © 2016, 2018-2024 Hmgle <[email protected]> | ||
|
||
根据 [GPLv3 许可](https://www.gnu.org/licenses/gpl-3.0.html)发布。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
/* | ||
* graftcp | ||
* Copyright (C) 2021, 2023 Hmgle <[email protected]> | ||
* Copyright (C) 2021, 2023, 2024 Hmgle <[email protected]> | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
/* | ||
* graftcp | ||
* Copyright (C) 2021 Hmgle <[email protected]> | ||
* Copyright (C) 2021, 2024 Hmgle <[email protected]> | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
/* | ||
* graftcp | ||
* Copyright (C) 2016, 2018-2023 Hmgle <[email protected]> | ||
* Copyright (C) 2016, 2018-2024 Hmgle <[email protected]> | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
|