• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Gallopsled / pwntools / 7250412654

18 Dec 2023 03:44PM UTC coverage: 74.547% (+0.1%) from 74.452%
7250412654

push

github

web-flow
Merge branch 'dev' into retguard

4565 of 7244 branches covered (0.0%)

350 of 507 new or added lines in 17 files covered. (69.03%)

13 existing lines in 5 files now uncovered.

12843 of 17228 relevant lines covered (74.55%)

0.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.64
/pwnlib/commandline/libcdb.py
1
#!/usr/bin/env python
2
from __future__ import absolute_import
1✔
3
from __future__ import division
1✔
4
from __future__ import print_function
1✔
5

6
import re
1✔
7
import shutil
1✔
8
import sys
1✔
9

10
import pwnlib.args
1✔
11
pwnlib.args.free_form = False
1✔
12

13
from pwn import *
1✔
14
from pwnlib.commandline import common
1✔
15

16
parser = common.parser_commands.add_parser(
1✔
17
    'libcdb',
18
    help = 'Print various information about a libc binary',
19
    description = 'Print various information about a libc binary'
20
)
21

22
libc_commands = parser.add_subparsers(
1✔
23
    dest = 'libc_command'
24
)
25

26
lookup_parser = libc_commands.add_parser(
1✔
27
    'lookup',
28
    help = 'Lookup a libc version by function offsets',
29
    description = 'Lookup a libc version by function offsets'
30
)
31

32
lookup_parser.add_argument(
1✔
33
    'symbol_offset_pairs',
34
    metavar = 'symbol_offset_pairs',
35
    nargs = '+',
36
    help = 'Symbol and offset pairs to lookup matching libc version. Can be any number of pairs to narrow the search. Example: "read 3e0 write 520"'
37
)
38

39
lookup_parser.add_argument(
1✔
40
    '--download-libc',
41
    action = 'store_true',
42
    default = False,
43
    help = 'Attempt to download the matching libc.so'
44
)
45

46
lookup_parser.add_argument(
1✔
47
    '--unstrip',
48
    action = 'store_true',
49
    default = True,
50
    help = 'Attempt to unstrip the libc binary with debug symbols from a debuginfod server'
51
)
52

53
lookup_parser.add_argument(
1✔
54
    '--no-unstrip',
55
    action = 'store_false',
56
    dest = 'unstrip',
57
    help = 'Do NOT attempt to unstrip the libc binary with debug symbols from a debuginfod server'
58
)
59

60
hash_parser = libc_commands.add_parser(
1✔
61
    'hash',
62
    help = 'Display information of a libc version given an unique hash',
63
    description = 'Display information of a libc version given an unique hash'
64
)
65

66
hash_parser.add_argument(
1✔
67
    'hash_value',
68
    metavar = 'hash_value',
69
    nargs = '+',
70
    help = 'Hex encoded hash value'
71
)
72

73
hash_parser.add_argument(
1✔
74
    '-t', '--hash_type',
75
    nargs = '?',
76
    type = str,
77
    choices = ['id', 'buildid', 'md5', 'sha1', 'sha256'],
78
    default = 'buildid',
79
    help = 'The type of the provided hash value. Supported hashtypes: id, buildid, md5, sha1, sha256'
80
)
81

82
hash_parser.add_argument(
1✔
83
    '--download-libc',
84
    action = 'store_true',
85
    default = False,
86
    help = 'Attempt to download the matching libc.so'
87
)
88

89
hash_parser.add_argument(
1✔
90
    '--unstrip',
91
    action = 'store_true',
92
    default = True,
93
    help = 'Attempt to unstrip the libc binary with debug symbols from a debuginfod server'
94
)
95

96
hash_parser.add_argument(
1✔
97
    '--no-unstrip',
98
    action = 'store_false',
99
    dest = 'unstrip',
100
    help = 'Do NOT attempt to unstrip the libc binary with debug symbols from a debuginfod server'
101
)
102

103
file_parser = libc_commands.add_parser(
1✔
104
    'file',
105
    help = 'Dump information about a libc binary',
106
    description = 'Dump information about a libc binary'
107
)
108

109
file_parser.add_argument(
1✔
110
    'files',
111
    metavar = 'files',
112
    nargs = '+',
113
    help = 'Libc binary to dump'
114
)
115

116
file_parser.add_argument(
1✔
117
    '-s', '--symbols',
118
    metavar = 'symbols',
119
    nargs = '*',
120
    help = 'List of symbol offsets to dump in addition to the common ones'
121
)
122

123
file_parser.add_argument(
1✔
124
    '-o', '--offset',
125
    metavar = 'offset',
126
    type = str,
127
    help = 'Display all offsets relative to this symbol'
128
)
129

130
file_parser.add_argument(
1✔
131
    '--unstrip',
132
    action = 'store_true',
133
    default = False,
134
    help = 'Attempt to unstrip the libc binary inplace with debug symbols from a debuginfod server'
135
)
136

137
common_symbols = ['dup2', 'printf', 'puts', 'read', 'system', 'write']
1✔
138

139
def find_libc(params):
1✔
140
    import requests
1✔
141
    url    = "https://libc.rip/api/find"
1✔
142
    result = requests.post(url, json=params, timeout=20)
1✔
143
    log.debug('Request: %s', params)
1✔
144
    log.debug('Result: %s', result.json())
1✔
145
    if result.status_code != 200 or len(result.json()) == 0:
1!
146
        log.failure("Could not find libc for %s on libc.rip", params)
×
147
        return []
×
148

149
    return result.json()
1✔
150

151
def print_libc(libc):
1✔
152
    log.info('%s', text.red(libc['id']))
1✔
153
    log.indented('\t%-20s %s', text.green('BuildID:'), libc['buildid'])
1✔
154
    log.indented('\t%-20s %s', text.green('MD5:'), libc['md5'])
1✔
155
    log.indented('\t%-20s %s', text.green('SHA1:'), libc['sha1'])
1✔
156
    log.indented('\t%-20s %s', text.green('SHA256:'), libc['sha256'])
1✔
157
    log.indented('\t%s', text.green('Symbols:'))
1✔
158
    for symbol in libc['symbols'].items():
1✔
159
        log.indented('\t%25s = %s', symbol[0], symbol[1])
1✔
160

161
def handle_remote_libc(args, libc):
1✔
162
    print_libc(libc)
1✔
163
    if args.download_libc:
1!
164
        path = libcdb.search_by_build_id(libc['buildid'], args.unstrip)
×
165
        if path:
×
166
            if args.unstrip:
×
167
                libcdb.unstrip_libc(path)
×
168
            shutil.copy(path, './{}.so'.format(libc['id']))
×
169

170
def translate_offset(offs, args, exe):
1✔
171
    if args.offset:
1!
172
        if args.offset not in exe.symbols:
×
173
            log.info_once('offset symbol %s not found. ignoring.', args.offset)
×
174
            return offs
×
175
        return offs - exe.symbols[args.offset]
×
176
    return offs
1✔
177

178
def collect_synthetic_symbols(exe):
1✔
179
    available_symbols = []
1✔
180
    try:
1✔
181
        exe.symbols['str_bin_sh'] = next(exe.search(b'/bin/sh\x00'))
1✔
182
        available_symbols.append('str_bin_sh')
1✔
NEW
183
    except StopIteration:
×
NEW
184
        pass
×
185
        
186
    libc_start_main_return = exe.libc_start_main_return
1✔
187
    if libc_start_main_return > 0:
1!
188
        exe.symbols['__libc_start_main_ret'] = libc_start_main_return
1✔
189
        available_symbols.append('__libc_start_main_ret')
1✔
190

191
    return available_symbols
1✔
192

193
def main(args):
1✔
194
    if len(sys.argv) < 3:
1!
195
        parser.print_usage()
×
196
        sys.exit()
×
197

198
    if args.libc_command == 'lookup':
1✔
199
        pairs = args.symbol_offset_pairs
1✔
200
        if len(pairs) % 2 != 0:
1!
201
            log.failure('Uneven number of arguments. Please provide "symbol offset" pairs')
×
202
            return
×
203
        
204
        symbols = {pairs[i]:pairs[i+1] for i in range(0, len(pairs), 2)}
1✔
205
        matched_libcs = find_libc({'symbols': symbols})
1✔
206
        for libc in matched_libcs:
1✔
207
            handle_remote_libc(args, libc)
1✔
208

209
    elif args.libc_command == 'hash':
1✔
210
        for hash_value in args.hash_value:
1✔
211
            matched_libcs = find_libc({args.hash_type: hash_value})
1✔
212
            for libc in matched_libcs:
1✔
213
                handle_remote_libc(args, libc)
1✔
214

215
    elif args.libc_command == 'file':
1!
216
        from hashlib import md5, sha1, sha256
1✔
217
        for file in args.files:
1✔
218
            if not os.path.exists(file) or not os.path.isfile(file):
1!
219
                log.failure('File does not exist %s', args.file)
×
220
                continue
×
221
            
222
            if args.unstrip:
1!
223
                libcdb.unstrip_libc(file)
×
224

225
            exe = ELF(file, checksec=False)
1✔
226
            log.info('%s', text.red(os.path.basename(file)))
1✔
227

228
            libc_version = re.search(br'libc[ -](\d+\.\d+)', exe.data)
1✔
229
            if libc_version:
1!
230
                log.indented('%-20s %s', text.green('Version:'), libc_version.group(1).decode())
1✔
231

232
            if exe.buildid:
1!
233
                log.indented('%-20s %s', text.green('BuildID:'), enhex(exe.buildid))
1✔
234
            log.indented('%-20s %s', text.green('MD5:'), md5(exe.data).hexdigest())
1✔
235
            log.indented('%-20s %s', text.green('SHA1:'), sha1(exe.data).hexdigest())
1✔
236
            log.indented('%-20s %s', text.green('SHA256:'), sha256(exe.data).hexdigest())
1✔
237

238
            # Always dump the basic list of common symbols
239
            log.indented('%s', text.green('Symbols:'))
1✔
240
            synthetic_symbols = collect_synthetic_symbols(exe)
1✔
241

242
            symbols = common_symbols + (args.symbols or []) + synthetic_symbols
1✔
243
            symbols.sort()
1✔
244
            for symbol in symbols:
1✔
245
                if symbol not in exe.symbols:
1!
246
                    log.indented('%25s = %s', symbol, text.red('not found'))
×
247
                else:
248
                    log.indented('%25s = %#x', symbol, translate_offset(exe.symbols[symbol], args, exe))
1✔
249

250
if __name__ == '__main__':
1✔
251
    pwnlib.commandline.common.main(__file__)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc