Skip to content

Commit c8dd161

Browse files
authored
Merge branch 'dev' into elf_stripped
2 parents b507f32 + 27bc31e commit c8dd161

File tree

11 files changed

+222
-43
lines changed

11 files changed

+222
-43
lines changed

.github/workflows/android.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- uses: actions/checkout@v4
1515

1616
- name: Cache for pip
17-
uses: actions/cache@v3
17+
uses: actions/cache@v4
1818
id: cache-pip
1919
with:
2020
path: ~/.cache/pip

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
git log --oneline --graph -10
2121
2222
- name: Cache for pip
23-
uses: actions/cache@v3
23+
uses: actions/cache@v4
2424
id: cache-pip
2525
with:
2626
path: ~/.cache/pip

.github/workflows/lint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
steps:
1313
- uses: actions/checkout@v4
1414
- name: Cache for pip
15-
uses: actions/cache@v3
15+
uses: actions/cache@v4
1616
id: cache-pip
1717
with:
1818
path: ~/.cache/pip

.github/workflows/pylint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
steps:
1313
- uses: actions/checkout@v4
1414
- name: Cache for pip
15-
uses: actions/cache@v3
15+
uses: actions/cache@v4
1616
id: cache-pip
1717
with:
1818
path: ~/.cache/pip

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ The table below shows which release corresponds to each branch, and what date th
8282
- [#2310][2310] Add support to start a process on Windows
8383
- [#2334][2334] Speed up disasm commandline tool with colored output
8484
- [#2328][2328] Lookup using $PATHEXT file extensions in `which` on Windows
85+
- [#2189][2189] Explicitly define p64/u64 functions for IDE support
86+
- [#2339][2339] Fix: Allow setting attributes on gdb Breakpoints
87+
- [#2323][2323] Retry failed lookups after one week in libcdb
88+
- [#2325][2325] Match against local system libc first in libcdb
8589
- [#2336][2336] Add `ELF.stripped` and `ELF.debuginfo` properties
8690

8791
[2242]: https://github.com/Gallopsled/pwntools/pull/2242
@@ -96,6 +100,10 @@ The table below shows which release corresponds to each branch, and what date th
96100
[2310]: https://github.com/Gallopsled/pwntools/pull/2310
97101
[2334]: https://github.com/Gallopsled/pwntools/pull/2334
98102
[2328]: https://github.com/Gallopsled/pwntools/pull/2328
103+
[2189]: https://github.com/Gallopsled/pwntools/pull/2189
104+
[2339]: https://github.com/Gallopsled/pwntools/pull/2339
105+
[2323]: https://github.com/Gallopsled/pwntools/pull/2323
106+
[2325]: https://github.com/Gallopsled/pwntools/pull/2325
99107
[2336]: https://github.com/Gallopsled/pwntools/pull/2336
100108

101109
## 4.12.0 (`beta`)

pwnlib/gdb.py

+27-10
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,10 @@ def __init__(self, conn, *args, **kwargs):
652652
"""
653653
# Creates a real breakpoint and connects it with this mirror
654654
self.conn = conn
655-
self.server_breakpoint = conn.root.set_breakpoint(
655+
self.server_breakpoint = self._server_set_breakpoint(*args, **kwargs)
656+
657+
def _server_set_breakpoint(self, *args, **kwargs):
658+
return self.conn.root.set_breakpoint(
656659
self, hasattr(self, 'stop'), *args, **kwargs)
657660

658661
def __getattr__(self, item):
@@ -670,25 +673,43 @@ def __getattr__(self, item):
670673
raise AttributeError()
671674
return getattr(self.server_breakpoint, item)
672675

676+
def __setattr__(self, name, value):
677+
"""Set attributes of the real breakpoint."""
678+
if name in (
679+
'enabled',
680+
'silent',
681+
'thread',
682+
'task',
683+
'ignore_count',
684+
'hit_count'
685+
'condition',
686+
'commands',
687+
):
688+
return setattr(self.server_breakpoint, name, value)
689+
return super().__setattr__(name, value)
690+
673691
def exposed_stop(self):
674692
# Handle stop() call from the server.
675693
return self.stop()
676694

677-
class FinishBreakpoint:
695+
class FinishBreakpoint(Breakpoint):
678696
"""Mirror of ``gdb.FinishBreakpoint`` class.
679697
680698
See https://sourceware.org/gdb/onlinedocs/gdb/Finish-Breakpoints-in-Python.html
681699
for more information.
682700
"""
683701

684-
def __init__(self, conn, *args, **kwargs):
702+
def __init__(self, *args, **kwargs):
685703
"""Do not create instances of this class directly.
686704
687705
Use ``pwnlib.gdb.Gdb.FinishBreakpoint`` instead.
688706
"""
689-
# Creates a real finish breakpoint and connects it with this mirror
690-
self.conn = conn
691-
self.server_breakpoint = conn.root.set_finish_breakpoint(
707+
# See https://github.com/pylint-dev/pylint/issues/4228
708+
# pylint: disable=useless-super-delegation
709+
super().__init__(*args, **kwargs)
710+
711+
def _server_set_breakpoint(self, *args, **kwargs):
712+
return self.conn.root.set_finish_breakpoint(
692713
self, hasattr(self, 'stop'), hasattr(self, 'out_of_scope'),
693714
*args, **kwargs)
694715

@@ -708,10 +729,6 @@ def __getattr__(self, item):
708729
raise AttributeError()
709730
return getattr(self.server_breakpoint, item)
710731

711-
def exposed_stop(self):
712-
# Handle stop() call from the server.
713-
return self.stop()
714-
715732
def exposed_out_of_scope(self):
716733
# Handle out_of_scope() call from the server.
717734
return self.out_of_scope()

pwnlib/gdb_api_bridge.py

+1
Original file line numberDiff line numberDiff line change
@@ -110,5 +110,6 @@ def exposed_quit(self):
110110
socket_path=socket_path,
111111
protocol_config={
112112
'allow_all_attrs': True,
113+
'allow_setattr': True,
113114
},
114115
).start)

pwnlib/libcdb.py

+41-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from __future__ import division
66

77
import os
8+
import time
89
import six
910
import tempfile
1011

@@ -13,14 +14,20 @@
1314
from pwnlib.log import getLogger
1415
from pwnlib.tubes.process import process
1516
from pwnlib.util.fiddling import enhex
17+
from pwnlib.util.hashes import sha1filehex, sha256filehex, md5filehex
1618
from pwnlib.util.misc import read
1719
from pwnlib.util.misc import which
1820
from pwnlib.util.misc import write
1921
from pwnlib.util.web import wget
2022

2123
log = getLogger(__name__)
2224

23-
HASHES = ['build_id', 'sha1', 'sha256', 'md5']
25+
HASHES = {
26+
'build_id': lambda path: enhex(ELF(path, checksec=False).buildid or b''),
27+
'sha1': sha1filehex,
28+
'sha256': sha256filehex,
29+
'md5': md5filehex,
30+
}
2431
DEBUGINFOD_SERVERS = [
2532
'https://debuginfod.elfutils.org/',
2633
]
@@ -29,6 +36,9 @@
2936
urls = os.environ['DEBUGINFOD_URLS'].split(' ')
3037
DEBUGINFOD_SERVERS = urls + DEBUGINFOD_SERVERS
3138

39+
# Retry failed lookups after some time
40+
NEGATIVE_CACHE_EXPIRY = 60 * 60 * 24 * 7 # 1 week
41+
3242
# https://gitlab.com/libcdb/libcdb wasn't updated after 2019,
3343
# but still is a massive database of older libc binaries.
3444
def provider_libcdb(hex_encoded_id, hash_type):
@@ -100,7 +110,23 @@ def provider_libc_rip(hex_encoded_id, hash_type):
100110
return None
101111
return data
102112

103-
PROVIDERS = [provider_libcdb, provider_libc_rip]
113+
# Check if the local system libc matches the requested hash.
114+
def provider_local_system(hex_encoded_id, hash_type):
115+
if hash_type == 'id':
116+
return None
117+
shell_path = os.environ.get('SHELL', None) or '/bin/sh'
118+
if not os.path.exists(shell_path):
119+
log.debug('Shell path %r does not exist. Skipping local system libc matching.', shell_path)
120+
return None
121+
local_libc = ELF(shell_path, checksec=False).libc
122+
if not local_libc:
123+
log.debug('Cannot lookup libc from shell %r. Skipping local system libc matching.', shell_path)
124+
return None
125+
if HASHES[hash_type](local_libc.path) == hex_encoded_id:
126+
return local_libc.data
127+
return None
128+
129+
PROVIDERS = [provider_local_system, provider_libcdb, provider_libc_rip]
104130

105131
def search_by_hash(hex_encoded_id, hash_type='build_id', unstrip=True):
106132
assert hash_type in HASHES, hash_type
@@ -109,6 +135,10 @@ def search_by_hash(hex_encoded_id, hash_type='build_id', unstrip=True):
109135
cache, cache_valid = _check_elf_cache('libcdb', hex_encoded_id, hash_type)
110136
if cache_valid:
111137
return cache
138+
139+
# We searched for this buildid before, but didn't find anything.
140+
if cache is None:
141+
return None
112142

113143
# Run through all available libc database providers to see if we have a match.
114144
for provider in PROVIDERS:
@@ -141,6 +171,10 @@ def _search_debuginfo_by_hash(base_url, hex_encoded_id):
141171
cache, cache_valid = _check_elf_cache('libcdb_dbg', hex_encoded_id, 'build_id')
142172
if cache_valid:
143173
return cache
174+
175+
# We searched for this buildid before, but didn't find anything.
176+
if cache is None:
177+
return None
144178

145179
# Try to find separate debuginfo.
146180
url = '/buildid/{}/debuginfo'.format(hex_encoded_id)
@@ -191,8 +225,11 @@ def _check_elf_cache(cache_type, hex_encoded_id, hash_type):
191225

192226
data = read(cache)
193227
if not data.startswith(b'\x7FELF'):
194-
log.info_once("Skipping unavailable ELF %s", hex_encoded_id)
195-
return cache, False
228+
# Retry failed lookups after some time
229+
if time.time() > os.path.getmtime(cache) + NEGATIVE_CACHE_EXPIRY:
230+
return cache, False
231+
log.info_once("Skipping invalid cached ELF %s", hex_encoded_id)
232+
return None, False
196233

197234
log.info_once("Using cached data from %r", cache)
198235
return cache, True

pwnlib/tubes/ssh.py

+1
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ def libs(self):
324324

325325
for lib in maps:
326326
remote_path = lib.split(self.parent.host)[-1]
327+
remote_path = self.parent.readlink('-f', remote_path).decode()
327328
for line in maps_raw.splitlines():
328329
if line.endswith(remote_path):
329330
address = line.split('-')[0]

pwnlib/util/misc.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ def run_in_new_terminal(command, terminal=None, args=None, kill_at_exit=True, pr
307307
elif 'STY' in os.environ and which('screen'):
308308
terminal = 'screen'
309309
args = ['-t','pwntools-gdb','bash','-c']
310-
elif 'TERM_PROGRAM' in os.environ:
310+
elif 'TERM_PROGRAM' in os.environ and which(os.environ['TERM_PROGRAM']):
311311
terminal = os.environ['TERM_PROGRAM']
312312
args = []
313313
elif 'DISPLAY' in os.environ and which('x-terminal-emulator'):

0 commit comments

Comments
 (0)