Skip to content

Commit

Permalink
Merge branch 'dev' into better-got
Browse files Browse the repository at this point in the history
  • Loading branch information
Arusekk authored Nov 14, 2023
2 parents c66457e + b53d476 commit de1890a
Show file tree
Hide file tree
Showing 14 changed files with 189 additions and 38 deletions.
14 changes: 7 additions & 7 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,40 @@ jobs:
steps:
# Required for subdirectories in Git context
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3

- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}

- name: Build and push base image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
if: github.event_name == 'workflow_dispatch'
with:
context: "{{defaultContext}}:extra/docker/base"
push: true
tags: pwntools/pwntools:base

- name: Build and push stable image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/stable')
with:
context: "{{defaultContext}}:extra/docker/stable"
push: true
tags: pwntools/pwntools:stable

- name: Build and push beta image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/beta')
with:
context: "{{defaultContext}}:extra/docker/beta"
push: true
tags: pwntools/pwntools:beta

- name: Build and push dev image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/dev')
with:
context: "{{defaultContext}}:extra/docker/dev"
Expand All @@ -56,7 +56,7 @@ jobs:
pwntools/pwntools:latest
- name: Build and push ci image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/dev')
with:
context: "{{defaultContext}}:travis/docker"
Expand Down
24 changes: 22 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ The table below shows which release corresponds to each branch, and what date th
| ---------------- | -------- | ---------------------- |
| [4.13.0](#4130-dev) | `dev` |
| [4.12.0](#4120-beta) | `beta` |
| [4.11.0](#4110-stable) | `stable` | Sep 15, 2023
| [4.11.1](#4111-stable) | `stable` | Nov 14, 2023
| [4.11.0](#4110) | | Sep 15, 2023
| [4.10.0](#4100) | | May 21, 2023
| [4.9.0](#490) | | Dec 29, 2022
| [4.8.0](#480) | | Apr 21, 2022
Expand Down Expand Up @@ -69,9 +70,14 @@ The table below shows which release corresponds to each branch, and what date th

## 4.13.0 (`dev`)

- [#2281][2281] FIX: Getting right amount of data for search fix
- [#2293][2293] Add x86 CET status to checksec output

[2281]: https://github.com/Gallopsled/pwntools/pull/2281
[2293]: https://github.com/Gallopsled/pwntools/pull/2293

## 4.12.0 (`beta`)

- [#2202][2202] Fix `remote` and `listen` in sagemath
- [#2117][2117] Add -p (--prefix) and -s (--separator) arguments to `hex` command
- [#2221][2221] Add shellcraft.sleep template wrapping SYS_nanosleep
Expand All @@ -88,7 +94,21 @@ The table below shows which release corresponds to each branch, and what date th
[2257]: https://github.com/Gallopsled/pwntools/pull/2257
[2225]: https://github.com/Gallopsled/pwntools/pull/2225

## 4.11.0 (`stable`)
## 4.11.1 (`stable`)

- [#2271][2271] FIX: Generated shebang with path to python invalid if path contains spaces
- [#2272][2272] Fix `tube.clean_and_log` not logging buffered data
- [#2281][2281] FIX: Getting right amount of data for search fix
- [#2287][2287] Fix `_countdown_handler` not invoking `timeout_change`
- [#2294][2294] Fix atexit SEGV in aarch64 loader

[2271]: https://github.com/Gallopsled/pwntools/pull/2271
[2272]: https://github.com/Gallopsled/pwntools/pull/2272
[2281]: https://github.com/Gallopsled/pwntools/pull/2281
[2287]: https://github.com/Gallopsled/pwntools/pull/2287
[2294]: https://github.com/Gallopsled/pwntools/pull/2294

## 4.11.0

- [#2185][2185] make fmtstr module able to create payload without $ notation
- [#2103][2103] Add search for libc binary by leaked function addresses `libcdb.search_by_symbol_offsets()`
Expand Down
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ include *.md *.txt *.sh *.yml MANIFEST.in
recursive-include docs *.rst *.png Makefile *.py *.txt
recursive-include pwnlib *.py *.asm *.rst *.md *.txt *.sh __doc__ *.mako
recursive-include pwn *.py *.asm *.rst *.md *.txt *.sh
recursive-exclude *.pyc
global-exclude *.pyc
30 changes: 18 additions & 12 deletions examples/clean_and_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,24 @@
"""

from pwn import *
from multiprocessing import Process

os.system('''((
echo prefix sometext ;
echo prefix someothertext ;
echo here comes the flag ;
echo LostInTheInterTubes
) | nc -l 1337) &
''')
def submit_data():
with context.quiet:
with listen(1337) as io:
io.wait_for_connection()
io.sendline(b'prefix sometext')
io.sendline(b'prefix someothertext')
io.sendline(b'here comes the flag')
io.sendline(b'LostInTheInterTubes')

r = remote('localhost', 1337)
atexit.register(r.clean_and_log)
if __name__ == '__main__':
p = Process(target=submit_data)
p.start()

while True:
line = r.recvline()
print(re.findall(r'^prefix (\S+)$', line)[0])
r = remote('localhost', 1337)
atexit.register(r.clean_and_log)

while True:
line = r.recvline()
print(re.findall(br'^prefix (\S+)$', line)[0])
2 changes: 1 addition & 1 deletion extra/docker/beta/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ FROM pwntools/pwntools:stable

USER root
RUN python2.7 -m pip install --upgrade git+https://github.com/Gallopsled/pwntools@beta \
&& python3 -m pip install --upgrade git+https://github.com/Gallopsled/pwntools@beta
&& python3 -m pip install --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@beta
RUN PWNLIB_NOTERM=1 pwn update
USER pwntools
2 changes: 1 addition & 1 deletion extra/docker/dev/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ FROM pwntools/pwntools:stable

USER root
RUN python2.7 -m pip install --upgrade git+https://github.com/Gallopsled/pwntools@dev \
&& python3 -m pip install --upgrade git+https://github.com/Gallopsled/pwntools@dev
&& python3 -m pip install --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@dev
RUN PWNLIB_NOTERM=1 pwn update
USER pwntools
2 changes: 1 addition & 1 deletion extra/docker/stable/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ FROM pwntools/pwntools:base

USER root
RUN python2.7 -m pip install --upgrade git+https://github.com/Gallopsled/pwntools@stable \
&& python3 -m pip install --upgrade git+https://github.com/Gallopsled/pwntools@stable
&& python3 -m pip install --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@stable
RUN PWNLIB_NOTERM=1 pwn update
USER pwntools
60 changes: 58 additions & 2 deletions pwnlib/elf/elf.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
from elftools.elf.constants import SHN_INDICES
from elftools.elf.descriptions import describe_e_type
from elftools.elf.elffile import ELFFile
from elftools.elf.enums import ENUM_GNU_PROPERTY_X86_FEATURE_1_FLAGS
from elftools.elf.gnuversions import GNUVerDefSection
from elftools.elf.relocation import RelocationSection, RelrRelocationSection
from elftools.elf.sections import SymbolTableSection
Expand Down Expand Up @@ -510,6 +511,29 @@ def iter_segments_by_type(self, t):
if t == seg.header.p_type or t in str(seg.header.p_type):
yield seg

def iter_notes(self):
"""
Yields:
All the notes in the PT_NOTE segments. Each result is a dictionary-
like object with ``n_name``, ``n_type``, and ``n_desc`` fields, amongst
others.
"""
for seg in self.iter_segments_by_type('PT_NOTE'):
for note in seg.iter_notes():
yield note

def iter_properties(self):
"""
Yields:
All the GNU properties in the PT_NOTE segments. Each result is a dictionary-
like object with ``pr_type``, ``pr_datasz``, and ``pr_data`` fields.
"""
for note in self.iter_notes():
if note.n_type != 'NT_GNU_PROPERTY_TYPE_0':
continue
for prop in note.n_desc:
yield prop

def get_segment_for_address(self, address, size=1):
"""get_segment_for_address(address, size=1) -> Segment
Expand Down Expand Up @@ -1211,9 +1235,10 @@ def search(self, needle, writable = False, executable = False):
for seg in segments:
addr = seg.header.p_vaddr
memsz = seg.header.p_memsz
zeroed = memsz - seg.header.p_filesz
filesz = seg.header.p_filesz
zeroed = memsz - filesz
offset = seg.header.p_offset
data = self.mmap[offset:offset+memsz]
data = self.mmap[offset:offset+filesz]
data += b'\x00' * zeroed
offset = 0
while True:
Expand Down Expand Up @@ -2075,6 +2100,12 @@ def checksec(self, banner=True, color=True):

if self.ubsan:
res.append("UBSAN:".ljust(10) + green("Enabled"))

if self.shadowstack:
res.append("SHSTK:".ljust(10) + green("Enabled"))

if self.ibt:
res.append("IBT:".ljust(10) + green("Enabled"))

# Check for Linux configuration, it must contain more than
# just the version.
Expand Down Expand Up @@ -2132,6 +2163,31 @@ def ubsan(self):
""":class:`bool`: Whether the current binary was built with
Undefined Behavior Sanitizer (``UBSAN``)."""
return any(s.startswith('__ubsan_') for s in self.symbols)

@property
def shadowstack(self):
""":class:`bool`: Whether the current binary was built with
Shadow Stack (``SHSTK``)"""
if self.arch not in ['i386', 'amd64']:
return False
for prop in self.iter_properties():
if prop.pr_type != 'GNU_PROPERTY_X86_FEATURE_1_AND':
continue
return prop.pr_data & ENUM_GNU_PROPERTY_X86_FEATURE_1_FLAGS['GNU_PROPERTY_X86_FEATURE_1_SHSTK'] > 0
return False

@property
def ibt(self):
""":class:`bool`: Whether the current binary was built with
Indirect Branch Tracking (``IBT``)"""
if self.arch not in ['i386', 'amd64']:
return False
for prop in self.iter_properties():
if prop.pr_type != 'GNU_PROPERTY_X86_FEATURE_1_AND':
continue
return prop.pr_data & ENUM_GNU_PROPERTY_X86_FEATURE_1_FLAGS['GNU_PROPERTY_X86_FEATURE_1_IBT'] > 0
return False


def _update_args(self, kw):
kw.setdefault('arch', self.arch)
Expand Down
8 changes: 4 additions & 4 deletions pwnlib/shellcraft/templates/aarch64/linux/loader.asm
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,14 @@ PT_LOAD = 1
mov x3, sp
stp x2, x3, [sp, #-16]!

/* argc, argv[0], argv[1], envp */
/* argc, argv[0], argv[1], envp; x0 must be zero! */
/* ideally these could all be empty, but unfortunately
we have to keep the stack aligned. it's easier to
just push an extra argument than care... */
stp x0, x1, [sp, #-16]! /* argv[1] = NULL, envp = NULL */
mov x0, 1
mov x1, sp
stp x0, x1, [sp, #-16]! /* argc = 1, argv[0] = "" */
mov x2, 1
mov x3, sp
stp x2, x3, [sp, #-16]! /* argc = 1, argv[0] = "" */

br x8

Expand Down
4 changes: 3 additions & 1 deletion pwnlib/timeout.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ def __enter__(self):
self.obj._stop = min(self.obj._stop, self.old_stop)

self.obj._timeout = self.timeout
self.obj.timeout_change()
def __exit__(self, *a):
self.obj._timeout = self.old_timeout
self.obj._stop = self.old_stop
self.obj.timeout_change()

class _local_handler(object):
def __init__(self, obj, timeout):
Expand Down Expand Up @@ -157,7 +159,7 @@ def _get_timeout_seconds(self, value):
else:
value = float(value)

if value is value < 0:
if value < 0:
raise AttributeError("timeout: Timeout cannot be negative")

if value > self.maximum:
Expand Down
65 changes: 64 additions & 1 deletion pwnlib/tubes/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from pwnlib import term
from pwnlib.context import context, LocalContext
from pwnlib.exception import PwnlibException
from pwnlib.log import Logger
from pwnlib.log import getLogger
from pwnlib.term import text
Expand Down Expand Up @@ -613,6 +614,9 @@ def __init__(self, user=None, host=None, port=22, password=None, key=None,
self._platform_info = {}
self._aslr = None
self._aslr_ulimit = None
self._cpuinfo_cache = None
self._user_shstk = None
self._ibt = None

misc.mkdir_p(self._cachedir)

Expand Down Expand Up @@ -2144,6 +2148,57 @@ def preexec():

return self._aslr_ulimit

def _cpuinfo(self):
if self._cpuinfo_cache is None:
with context.quiet:
try:
self._cpuinfo_cache = self.read('/proc/cpuinfo')
except PwnlibException:
self._cpuinfo_cache = b''
return self._cpuinfo_cache

@property
def user_shstk(self):
""":class:`bool`: Whether userspace shadow stack is supported on the system.
Example:
>>> s = ssh("travis", "example.pwnme")
>>> s.user_shstk
False
"""
if self._user_shstk is None:
if self.os != 'linux':
self.warn_once("Only Linux is supported for userspace shadow stack checks.")
self._user_shstk = False

else:
cpuinfo = self._cpuinfo()

self._user_shstk = b' user_shstk' in cpuinfo
return self._user_shstk

@property
def ibt(self):
""":class:`bool`: Whether kernel indirect branch tracking is supported on the system.
Example:
>>> s = ssh("travis", "example.pwnme")
>>> s.ibt
False
"""
if self._ibt is None:
if self.os != 'linux':
self.warn_once("Only Linux is supported for kernel indirect branch tracking checks.")
self._ibt = False

else:
cpuinfo = self._cpuinfo()

self._ibt = b' ibt ' in cpuinfo or b' ibt\n' in cpuinfo
return self._ibt

def _checksec_cache(self, value=None):
path = self._get_cachefile('%s-%s' % (self.host, self.port))

Expand Down Expand Up @@ -2180,7 +2235,15 @@ def checksec(self, banner=True):
"ASLR:".ljust(10) + {
True: green("Enabled"),
False: red("Disabled")
}[self.aslr]
}[self.aslr],
"SHSTK:".ljust(10) + {
True: green("Enabled"),
False: red("Disabled")
}[self.user_shstk],
"IBT:".ljust(10) + {
True: green("Enabled"),
False: red("Disabled")
}[self.ibt],
]

if self.aslr_ulimit:
Expand Down
Loading

0 comments on commit de1890a

Please sign in to comment.