forked from lieanu/LibcSearcher
-
Notifications
You must be signed in to change notification settings - Fork 1
/
LibcSearcher.py
executable file
·128 lines (110 loc) · 4.45 KB
/
LibcSearcher.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/bin/env python
from __future__ import print_function
import os
import re
import sys
class LibcSearcher(object):
def __init__(self, func=None, address=None):
self.condition = {}
if func is not None and address is not None:
self.add_condition(func, address)
self.libc_database_path = os.path.join(
os.path.realpath(os.path.dirname(__file__)), "libc-database/db/")
self.db = ""
def add_condition(self, func, address):
if not isinstance(func, str):
print("The function should be a string")
sys.exit()
if not isinstance(address, int):
print("The address should be an int number")
sys.exit()
self.condition[func] = address
#Wrapper for libc-database's find shell script.
def decided(self):
if len(self.condition) == 0:
print("No leaked info provided.")
print("Please supply more info using add_condition(leaked_func, leaked_address).")
sys.exit(0)
res = []
for name, address in self.condition.items():
addr_last12 = address & 0xfff
# res.append(re.compile("^%s .*%x" % (name, addr_last12))) #后3位以0开头将丢失第一位,匹配精度下降,将出现大量结果;还可能匹配上地址中间部分,所以改为加%03x$
res.append(re.compile("^%s .*%03x$" % (name, addr_last12)))
db = self.libc_database_path
files = []
# only read "*.symbols" file to find
for _, _, f in os.walk(db):
for i in f:
files += re.findall('^.*symbols$', i)
result = {}
for ff in files:
fd = open(db + ff, "rb")
data = fd.read().decode(errors='ignore').split("\n")
for x in res:
if any(map(lambda line: x.match(line), data)):
try:
result[ff] += 1
except KeyError:
result[ff] = 1
fd.close()
result = sorted(result.items(), key=lambda x: x[1], reverse=True)
if len(result) == 0:
print("No matched libc, please add more libc or try others")
sys.exit(0)
if len(result) > 1:
print("Multi Results:")
for x in range(len(result)):
print("%2d:[hit %2d times] %s" % (x, result[x][1], self.pmore(result[x][0])))
print("Please supply more info using \n\tadd_condition(leaked_func, leaked_address).")
while True:
in_id = input(
"You can choose it by hand\nOr type 'exit' to quit:")
if in_id == "exit" or in_id == "quit":
sys.exit(0)
try:
in_id = int(in_id)
self.db = result[in_id][0]
break
except:
continue
else:
self.db = result[0][0]
print("[+] %s be choosed." % self.pmore(self.db))
def pmore(self, result):
result = result[:-8] # .strip(".symbols")
fd = open(self.libc_database_path + result + ".info")
info = fd.read().strip()
return("%s (id %s)" % (info, result))
#Wrapper for libc-database's dump shell script.
def dump(self, func=None):
if not self.db:
self.decided()
db = self.libc_database_path + self.db
fd = open(db, "rb")
data = fd.read().decode(errors='ignore').strip("\n").split("\n")
if not func:
result = {}
func = [
"__libc_start_main_ret", "system", "dup2", "read", "write",
"str_bin_sh"
]
for ff in func:
for d in data:
f = d.split(" ")[0]
addr = d.split(" ")[1]
if ff == f:
result[ff] = int(addr, 16)
for k, v in result.items():
print(k, hex(v))
return result
for d in data:
f = d.split(" ")[0]
addr = d.split(" ")[1]
if func == f:
return int(addr, 16)
print("No matched, Make sure you supply a valid function name or just add more libc.")
return 0
if __name__ == "__main__":
obj = LibcSearcher("fgets", 0x7ff39014bd90)
print("[+]system offset: ", hex(obj.dump("system")))
print("[+]/bin/sh offset: ", hex(obj.dump("str_bin_sh")))