Skip to content

Commit

Permalink
Merge branch 'dev' into dupio
Browse files Browse the repository at this point in the history
  • Loading branch information
Arusekk committed Aug 8, 2022
2 parents 79c29bb + 01df19d commit 79d7c99
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 25 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -66,8 +66,10 @@ The table below shows which release corresponds to each branch, and what date th

## 4.10.0 (`dev`)

- [#2062][2062] make pwn cyclic -l work with entry larger than 4 bytes
- [#2092][2092] shellcraft: dup() is now called dupio() consistently across all supported arches

[2062]: https://github.com/Gallopsled/pwntools/pull/2062
[2092]: https://github.com/Gallopsled/pwntools/pull/2092

## 4.9.0 (`beta`)
Expand Down
8 changes: 4 additions & 4 deletions docs/source/install/binutils.rst
Expand Up @@ -5,7 +5,7 @@ Assembly of foreign architectures (e.g. assembling Sparc shellcode on
Mac OS X) requires cross-compiled versions of ``binutils`` to be
installed. We've made this process as smooth as we can.

In these examples, replace ``$ARCH`` with your target architecture (e.g., arm, mips64, vax, etc.).
In these examples, replace ``$ARCH`` with your target architecture (e.g., arm, aarch64, mips64, vax, etc.).

Building `binutils` from source takes about 60 seconds on a modern 8-core machine.

Expand Down Expand Up @@ -51,10 +51,10 @@ OSes, ``binutils`` is simple to build by hand.
#!/usr/bin/env bash
V=2.25 # Binutils Version
V=2.38 # Binutils Version
ARCH=arm # Target architecture
cd /tmp
cd $TMP
wget -nc https://ftp.gnu.org/gnu/binutils/binutils-$V.tar.gz
wget -nc https://ftp.gnu.org/gnu/binutils/binutils-$V.tar.gz.sig
Expand All @@ -70,7 +70,7 @@ OSes, ``binutils`` is simple to build by hand.
export AS=as
../binutils-$V/configure \
--prefix=/usr/local \
--prefix=${PREFIX:-/usr/local} \
--target=$ARCH-unknown-linux-gnu \
--disable-static \
--disable-multilib \
Expand Down
7 changes: 5 additions & 2 deletions pwnlib/commandline/cyclic.py
Expand Up @@ -72,13 +72,16 @@ def main(args):

try:
pat = int(pat, 0)
pat = pack(pat, 'all')
except ValueError:
pass
pat = flat(pat, bytes=args.length)

if len(pat) != subsize:
log.critical('Subpattern must be %d bytes' % subsize)
if len(pat) < subsize:
log.critical('Subpattern must be at least %d bytes' % subsize)
sys.exit(1)
else:
pat = pat[:subsize]

if not all(c in alphabet for c in pat):
log.critical('Pattern contains characters not present in the alphabet')
Expand Down
52 changes: 33 additions & 19 deletions pwnlib/rop/ret2csu.py
Expand Up @@ -31,27 +31,34 @@ def ret2csu(rop, elf, edi, rsi, rdx, rbx, rbp, r12, r13, r14, r15, call=None):

# Resolve __libc_csu_ symbols if candidate binary is stripped
if '__libc_csu_init' not in elf.symbols:
if elf.pie:
for insn in md.disasm(elf.section('.text'),
elf.offset_to_vaddr(elf.get_section_by_name('.text').header['sh_offset'])):
if insn.mnemonic == 'lea' and insn.operands[0].reg == X86_REG_R8:
elf.sym['__libc_csu_fini'] = insn.address + insn.size + insn.disp
if insn.mnemonic == 'lea' and insn.operands[0].reg == X86_REG_RCX:
elf.sym['__libc_csu_init'] = insn.address + insn.size + insn.disp
textaddr = elf.offset_to_vaddr(elf.get_section_by_name('.text').header.sh_offset)
entry = elf.entry
data = elf.section('.text')[entry-textaddr:]
mnemonic = elf.pie and 'lea' or 'mov'
for insn in md.disasm(data, entry):
if insn.mnemonic == mnemonic:
if mnemonic == 'lea':
addr = insn.address + insn.size + insn.disp
else:
addr = insn.operands[1].imm

if insn.operands[0].reg == X86_REG_R8:
elf.sym['__libc_csu_fini'] = addr
if insn.operands[0].reg == X86_REG_RCX:
elf.sym['__libc_csu_init'] = addr
break
elif insn.mnemonic == 'xor' and insn.operands[0].reg == insn.operands[1].reg == X86_REG_ECX:
log.error("This binary is compiled for glibc 2.34+ and does not have __libc_csu_init")
elif insn.mnemonic in ('hlt', 'jmp', 'call', 'syscall'):
log.error("No __libc_csu_init (no glibc _start)")
else:
for insn in md.disasm(elf.section('.text'), elf.get_section_by_name('.text').header['sh_addr']):
if insn.mnemonic == 'mov' and insn.operands[0].reg == X86_REG_R8:
elf.sym['__libc_csu_fini'] = insn.operands[1].imm
if insn.mnemonic == 'mov' and insn.operands[0].reg == X86_REG_RCX:
elf.sym['__libc_csu_init'] = insn.operands[1].imm
break
log.error("Weird _start, definitely no __libc_csu_init")

# Resolve location of _fini address if required
if not elf.pie and not call:
fini = next(elf.search(p64(elf.dynamic_by_tag('DT_FINI')['d_ptr'])))
call = next(elf.search(p64(elf.dynamic_by_tag('DT_FINI')['d_ptr'])))
elif elf.pie and not call:
log.error('No non-PIE binaries in [elfs], \'call\' parameter is required')
log.error("No non-PIE binaries in [elfs], 'call' parameter is required")

csu_function = elf.read(elf.sym['__libc_csu_init'], elf.sym['__libc_csu_fini'] - elf.sym['__libc_csu_init'])

Expand All @@ -63,26 +70,33 @@ def ret2csu(rop, elf, edi, rsi, rdx, rbx, rbp, r12, r13, r14, r15, call=None):
# rbx and rbp must be equal after 'add rbx, 1'
rop.raw(0x00) # pop rbx
rop.raw(0x01) # pop rbp
if call:
rop.raw(call) # pop r12
else:
rop.raw(fini) # pop r12

# Older versions of gcc use r13 to populate rdx then r15d to populate edi, newer versions use the reverse
# Account for this when the binary was linked against a glibc that was built with a newer gcc
for insn in md.disasm(csu_function, elf.sym['__libc_csu_init']):
if insn.mnemonic == 'mov' and insn.operands[0].reg == X86_REG_RDX and insn.operands[1].reg == X86_REG_R13:
rop.raw(call) # pop r12
rop.raw(rdx) # pop r13
rop.raw(rsi) # pop r14
rop.raw(edi) # pop r15
rop.raw(insn.address)
break
elif insn.mnemonic == 'mov' and insn.operands[0].reg == X86_REG_RDX and insn.operands[1].reg == X86_REG_R14:
rop.raw(edi) # pop r12
rop.raw(rsi) # pop r13
rop.raw(rdx) # pop r14
rop.raw(call) # pop r15
rop.raw(insn.address)
break
elif insn.mnemonic == 'mov' and insn.operands[0].reg == X86_REG_RDX and insn.operands[1].reg == X86_REG_R15:
rop.raw(call) # pop r12
rop.raw(edi) # pop r13
rop.raw(rsi) # pop r14
rop.raw(rdx) # pop r15
rop.raw(insn.address)
break
else:
log.error("This CSU init variant is not supported by pwntools")

# 2nd gadget: Populate edi, rsi & rdx. Populate optional registers
rop.raw(Padding('<add rsp, 8>')) # add rsp, 8
Expand Down

0 comments on commit 79d7c99

Please sign in to comment.