From ee0a6175d95d3705f3bbbe15c59c0e835cde25d0 Mon Sep 17 00:00:00 2001 From: david942j Date: Wed, 7 Aug 2024 23:34:21 +0800 Subject: [PATCH] Upgrade to Ruby >= 3.1 (#216) --- .github/workflows/ruby.yml | 2 +- Gemfile.lock | 51 +-- README.md | 399 ++++++++++++++++++------ lib/one_gadget/cli.rb | 8 +- lib/one_gadget/emulators/aarch64.rb | 4 +- lib/one_gadget/emulators/instruction.rb | 2 +- lib/one_gadget/emulators/lambda.rb | 6 +- lib/one_gadget/emulators/processor.rb | 2 +- lib/one_gadget/emulators/x86.rb | 2 +- lib/one_gadget/fetcher.rb | 2 +- lib/one_gadget/fetchers/base.rb | 13 +- lib/one_gadget/gadget.rb | 6 +- lib/one_gadget/helper.rb | 4 +- lib/one_gadget/update.rb | 4 +- one_gadget.gemspec | 6 +- spec/emulators/i386_spec.rb | 2 +- spec/emulators/instruction_spec.rb | 10 +- spec/emulators/lambda_spec.rb | 2 +- spec/helper_spec.rb | 6 +- tasks/builds/generate.rake | 4 +- tasks/builds/list.rake | 2 +- 21 files changed, 373 insertions(+), 164 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 3d7e1b45..629acf77 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -13,7 +13,7 @@ jobs: continue-on-error: ${{ matrix.ruby-version == 'head' }} strategy: matrix: - ruby-version: ['2.6', '2.7', '3.0', '3.1', 'head'] + ruby-version: ['3.1', '3.2', '3.3', 'head'] steps: - uses: actions/checkout@v2 diff --git a/Gemfile.lock b/Gemfile.lock index 3d8d1847..3d1ab4cb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,54 +8,63 @@ GEM remote: https://rubygems.org/ specs: ast (2.4.2) - bindata (2.4.15) + bindata (2.5.0) diff-lcs (1.5.1) - docile (1.4.0) + docile (1.4.1) elftools (1.1.3) bindata (~> 2) - parallel (1.22.1) - parser (3.1.2.0) + json (2.7.2) + language_server-protocol (3.17.0.3) + parallel (1.25.1) + parser (3.3.4.0) ast (~> 2.4.1) + racc + racc (1.8.1) rainbow (3.1.1) - rake (13.1.0) - regexp_parser (2.3.1) - rexml (3.2.5) + rake (13.2.1) + regexp_parser (2.9.2) + rexml (3.3.4) + strscan rspec (3.13.0) rspec-core (~> 3.13.0) rspec-expectations (~> 3.13.0) rspec-mocks (~> 3.13.0) rspec-core (3.13.0) rspec-support (~> 3.13.0) - rspec-expectations (3.13.0) + rspec-expectations (3.13.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-mocks (3.13.0) + rspec-mocks (3.13.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-support (3.13.1) - rubocop (1.28.2) + rubocop (1.65.1) + json (~> 2.3) + language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.1.0.0) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.17.0, < 2.0) + regexp_parser (>= 2.4, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.17.0) - parser (>= 3.1.1.0) - ruby-progressbar (1.11.0) - simplecov (0.21.2) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.32.0) + parser (>= 3.3.1.0) + ruby-progressbar (1.13.0) + simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) - unicode-display_width (2.1.0) + strscan (3.1.0) + unicode-display_width (2.5.0) yard (0.9.36) PLATFORMS ruby + x86_64-linux DEPENDENCIES one_gadget! @@ -66,4 +75,4 @@ DEPENDENCIES yard (~> 0.9) BUNDLED WITH - 2.1.4 + 2.5.3 diff --git a/README.md b/README.md index 00d462f6..ea8f3633 100644 --- a/README.md +++ b/README.md @@ -64,18 +64,20 @@ $ one_gadget ```bash $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 -# 0x4f2c5 execve("/bin/sh", rsp+0x40, environ) +# 0xe3afe execve("/bin/sh", r15, r12) # constraints: -# rsp & 0xf == 0 -# rcx == NULL +# [r15] == NULL || r15 == NULL || r15 is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp # -# 0x4f322 execve("/bin/sh", rsp+0x40, environ) +# 0xe3b01 execve("/bin/sh", r15, rdx) # constraints: -# [rsp+0x40] == NULL +# [r15] == NULL || r15 == NULL || r15 is a valid argv +# [rdx] == NULL || rdx == NULL || rdx is a valid envp # -# 0x10a38c execve("/bin/sh", rsp+0x70, environ) +# 0xe3b04 execve("/bin/sh", rsi, rdx) # constraints: -# [rsp+0x70] == NULL +# [rsi] == NULL || rsi == NULL || rsi is a valid argv +# [rdx] == NULL || rdx == NULL || rdx is a valid envp ``` ![x86_64](https://github.com/david942j/one_gadget/blob/master/examples/x86_64.png?raw=true) @@ -83,21 +85,17 @@ $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 #### Given BuildID ```bash $ one_gadget -b aad7dbe330f23ea00ca63daf793b766b51aceb5d -# 0x45526 execve("/bin/sh", rsp+0x30, environ) -# constraints: -# rax == NULL -# # 0x4557a execve("/bin/sh", rsp+0x30, environ) # constraints: -# [rsp+0x30] == NULL +# [rsp+0x30] == NULL || {[rsp+0x30], [rsp+0x38], [rsp+0x40], [rsp+0x48], ...} is a valid argv # # 0xf1651 execve("/bin/sh", rsp+0x40, environ) # constraints: -# [rsp+0x40] == NULL +# [rsp+0x40] == NULL || {[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...} is a valid argv # # 0xf24cb execve("/bin/sh", rsp+0x60, environ) # constraints: -# [rsp+0x60] == NULL +# [rsp+0x60] == NULL || {[rsp+0x60], [rsp+0x68], [rsp+0x70], [rsp+0x78], ...} is a valid argv ``` ![build id](https://github.com/david942j/one_gadget/blob/master/examples/from_build_id.png?raw=true) @@ -120,33 +118,37 @@ Reorder gadgets according to the distance of given functions. ```bash $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near exit,mkdir -# [OneGadget] Gadgets near exit(0x43120): -# 0x4f2c5 execve("/bin/sh", rsp+0x40, environ) +# [OneGadget] Gadgets near exit(0x46a40): +# 0xe3afe execve("/bin/sh", r15, r12) # constraints: -# rsp & 0xf == 0 -# rcx == NULL +# [r15] == NULL || r15 == NULL || r15 is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp # -# 0x4f322 execve("/bin/sh", rsp+0x40, environ) +# 0xe3b01 execve("/bin/sh", r15, rdx) # constraints: -# [rsp+0x40] == NULL +# [r15] == NULL || r15 == NULL || r15 is a valid argv +# [rdx] == NULL || rdx == NULL || rdx is a valid envp # -# 0x10a38c execve("/bin/sh", rsp+0x70, environ) +# 0xe3b04 execve("/bin/sh", rsi, rdx) # constraints: -# [rsp+0x70] == NULL +# [rsi] == NULL || rsi == NULL || rsi is a valid argv +# [rdx] == NULL || rdx == NULL || rdx is a valid envp # -# [OneGadget] Gadgets near mkdir(0x10fbb0): -# 0x10a38c execve("/bin/sh", rsp+0x70, environ) +# [OneGadget] Gadgets near mkdir(0x10de70): +# 0xe3b04 execve("/bin/sh", rsi, rdx) # constraints: -# [rsp+0x70] == NULL +# [rsi] == NULL || rsi == NULL || rsi is a valid argv +# [rdx] == NULL || rdx == NULL || rdx is a valid envp # -# 0x4f322 execve("/bin/sh", rsp+0x40, environ) +# 0xe3b01 execve("/bin/sh", r15, rdx) # constraints: -# [rsp+0x40] == NULL +# [r15] == NULL || r15 == NULL || r15 is a valid argv +# [rdx] == NULL || rdx == NULL || rdx is a valid envp # -# 0x4f2c5 execve("/bin/sh", rsp+0x40, environ) +# 0xe3afe execve("/bin/sh", r15, r12) # constraints: -# rsp & 0xf == 0 -# rcx == NULL +# [r15] == NULL || r15 == NULL || r15 is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp # ``` @@ -155,11 +157,11 @@ $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near exit,mkdir Regular expression is acceptable. ```bash $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near 'write.*' --raw -# [OneGadget] Gadgets near writev(0x1166a0): -# 1090444 324386 324293 +# [OneGadget] Gadgets near writev(0x114690): +# 932612 932609 932606 # -# [OneGadget] Gadgets near write(0x110140): -# 1090444 324386 324293 +# [OneGadget] Gadgets near write(0x10e280): +# 932612 932609 932606 # ``` @@ -167,23 +169,23 @@ $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near 'write.*' --raw Pass an ELF file as the argument, OneGadget will take all GOT functions for processing. ```bash $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --near spec/data/test_near_file.elf --raw -# [OneGadget] Gadgets near exit(0x43120): -# 324293 324386 1090444 +# [OneGadget] Gadgets near exit(0x46a40): +# 932606 932609 932612 # -# [OneGadget] Gadgets near puts(0x809c0): -# 324386 324293 1090444 +# [OneGadget] Gadgets near puts(0x84420): +# 932606 932609 932612 # -# [OneGadget] Gadgets near printf(0x64e80): -# 324386 324293 1090444 +# [OneGadget] Gadgets near printf(0x61c90): +# 932606 932609 932612 # -# [OneGadget] Gadgets near strlen(0x9dc70): -# 324386 324293 1090444 +# [OneGadget] Gadgets near strlen(0x9f630): +# 932606 932609 932612 # -# [OneGadget] Gadgets near __cxa_finalize(0x43520): -# 324293 324386 1090444 +# [OneGadget] Gadgets near __cxa_finalize(0x46f10): +# 932606 932609 932612 # -# [OneGadget] Gadgets near __libc_start_main(0x21ab0): -# 324293 324386 1090444 +# [OneGadget] Gadgets near __libc_start_main(0x23f90): +# 932606 932609 932612 # ``` @@ -197,89 +199,286 @@ Use option `--level 1` to show all gadgets found instead of only those with high ```bash $ one_gadget /lib/x86_64-linux-gnu/libc.so.6 --level 1 -# 0x4f2c5 execve("/bin/sh", rsp+0x40, environ) +# 0x51dfb posix_spawn(rsp+0xc, "/bin/sh", 0, rbp, rsp+0x50, environ) # constraints: +# address rsp+0x60 is writable # rsp & 0xf == 0 -# rcx == NULL +# {"sh", "-c", rbx, NULL} is a valid argv +# rbp == NULL || (u16)[rbp] == NULL # -# 0x4f322 execve("/bin/sh", rsp+0x40, environ) +# 0x51e02 posix_spawn(rsp+0xc, "/bin/sh", 0, rbp, rsp+0x50, environ) # constraints: -# [rsp+0x40] == NULL +# address rsp+0x60 is writable +# rsp & 0xf == 0 +# rax == NULL || {"sh", rax, rbx, NULL} is a valid argv +# rbp == NULL || (u16)[rbp] == NULL # -# 0xe569f execve("/bin/sh", r14, r12) +# 0x51e09 posix_spawn(rsp+0xc, "/bin/sh", 0, rbp, rsp+0x50, environ) # constraints: -# [r14] == NULL || r14 == NULL -# [r12] == NULL || r12 == NULL +# address rsp+0x60 is writable +# rsp & 0xf == 0 +# rcx == NULL || {rcx, rax, rbx, NULL} is a valid argv +# rbp == NULL || (u16)[rbp] == NULL # -# 0xe5858 execve("/bin/sh", [rbp-0x88], [rbp-0x70]) +# 0x51e10 posix_spawn(rsp+0xc, "/bin/sh", rdx, rbp, rsp+0x50, environ) # constraints: -# [[rbp-0x88]] == NULL || [rbp-0x88] == NULL -# [[rbp-0x70]] == NULL || [rbp-0x70] == NULL +# address rsp+0x60 is writable +# rsp & 0xf == 0 +# rcx == NULL || {rcx, (u64)xmm1, rbx, NULL} is a valid argv +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# rbp == NULL || (u16)[rbp] == NULL # -# 0xe585f execve("/bin/sh", r10, [rbp-0x70]) +# 0x51e15 posix_spawn(rsp+0xc, "/bin/sh", rdx, rbp, rsp+0x50, environ) # constraints: -# [r10] == NULL || r10 == NULL -# [[rbp-0x70]] == NULL || [rbp-0x70] == NULL +# address rsp+0x60 is writable +# rsp & 0xf == 0 +# (u64)xmm0 == NULL || {(u64)xmm0, (u64)xmm1, rbx, NULL} is a valid argv +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# rbp == NULL || (u16)[rbp] == NULL # -# 0xe5863 execve("/bin/sh", r10, rdx) +# 0x51e25 posix_spawn(rdi, "/bin/sh", rdx, rbp, rsp+0x50, [rax]) # constraints: -# [r10] == NULL || r10 == NULL -# [rdx] == NULL || rdx == NULL +# address rsp+0x60 is writable +# rsp & 0xf == 0 +# (u64)xmm0 == NULL || {(u64)xmm0, (u64)(xmm0 >> 64), rbx, NULL} is a valid argv +# [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp +# rdi == NULL || writable: rdi +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# rbp == NULL || (u16)[rbp] == NULL # -# 0x10a38c execve("/bin/sh", rsp+0x70, environ) +# 0x51e2a posix_spawn(rdi, "/bin/sh", rdx, rbp, r8, [rax]) # constraints: -# [rsp+0x70] == NULL +# address rsp+0x60 is writable +# rsp & 0xf == 0 +# [r8] == NULL || r8 is a valid argv +# [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp +# rdi == NULL || writable: rdi +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# rbp == NULL || (u16)[rbp] == NULL # -# 0x10a398 execve("/bin/sh", rsi, [rax]) +# 0x51e2d posix_spawn(rdi, "/bin/sh", rdx, rcx, r8, [rax]) # constraints: -# [rsi] == NULL || rsi == NULL -# [[rax]] == NULL || [rax] == NULL - -``` - -#### Other Architectures - -##### i386 -```bash -$ one_gadget /lib32/libc.so.6 -# 0x3cbea execve("/bin/sh", esp+0x34, environ) +# address rsp+0x60 is writable +# rsp & 0xf == 0 +# [r8] == NULL || r8 is a valid argv +# [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp +# rdi == NULL || writable: rdi +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# rcx == NULL || (u16)[rcx] == NULL +# +# 0x51e32 posix_spawn(rdi, "/bin/sh", rdx, rcx, r8, [rax]) # constraints: -# esi is the GOT address of libc -# [esp+0x34] == NULL +# address rsp+0x68 is writable +# rsp & 0xf == 0 +# [r8] == NULL || r8 is a valid argv +# [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp +# rdi == NULL || writable: rdi +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# rcx == NULL || (u16)[rcx] == NULL # -# 0x3cbec execve("/bin/sh", esp+0x38, environ) +# 0x84135 posix_spawn(rbx+0xe0, "/bin/sh", r12, 0, rsp+0x60, environ) # constraints: -# esi is the GOT address of libc -# [esp+0x38] == NULL +# address rsp+0x70 is writable +# rsp & 0xf == 0 +# {"sh", "-c", rbp, NULL} is a valid argv +# rbx+0xe0 == NULL || writable: rbx+0xe0 +# r12 == NULL || (s32)[r12+0x4] <= 0 # -# 0x3cbf0 execve("/bin/sh", esp+0x3c, environ) +# 0x8413c posix_spawn(rbx+0xe0, "/bin/sh", r12, 0, rsp+0x60, environ) # constraints: -# esi is the GOT address of libc -# [esp+0x3c] == NULL +# address rsp+0x70 is writable +# rsp & 0xf == 0 +# rax == NULL || {"sh", rax, rbp, NULL} is a valid argv +# rbx+0xe0 == NULL || writable: rbx+0xe0 +# r12 == NULL || (s32)[r12+0x4] <= 0 # -# 0x3cbf7 execve("/bin/sh", esp+0x40, environ) +# 0x84143 posix_spawn(rbx+0xe0, "/bin/sh", r12, 0, rsp+0x60, environ) # constraints: -# esi is the GOT address of libc -# [esp+0x40] == NULL +# address rsp+0x70 is writable +# rsp & 0xf == 0 +# rcx == NULL || {rcx, rax, rbp, NULL} is a valid argv +# rbx+0xe0 == NULL || writable: rbx+0xe0 +# r12 == NULL || (s32)[r12+0x4] <= 0 # -# 0x6729f execl("/bin/sh", eax) +# 0x84146 posix_spawn(rbx+0xe0, "/bin/sh", rdx, 0, rsp+0x60, environ) # constraints: -# esi is the GOT address of libc -# eax == NULL +# address rsp+0x70 is writable +# rsp & 0xf == 0 +# rcx == NULL || {rcx, rax, rbp, NULL} is a valid argv +# rbx+0xe0 == NULL || writable: rbx+0xe0 +# rdx == NULL || (s32)[rdx+0x4] <= 0 # -# 0x672a0 execl("/bin/sh", [esp]) +# 0x8414b posix_spawn(rbx+0xe0, "/bin/sh", rdx, 0, rsp+0x60, environ) # constraints: -# esi is the GOT address of libc -# [esp] == NULL +# address rsp+0x78 is writable +# rsp & 0xf == 0 +# rcx == NULL || {rcx, rax, [rsp+0x70], NULL} is a valid argv +# rbx+0xe0 == NULL || writable: rbx+0xe0 +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# +# 0x84150 posix_spawn(rbx+0xe0, "/bin/sh", rdx, 0, rsp+0x60, environ) +# constraints: +# address rsp+0x78 is writable +# rsp & 0xf == 0 +# rcx == NULL || {rcx, (u64)xmm1, [rsp+0x70], NULL} is a valid argv +# rbx+0xe0 == NULL || writable: rbx+0xe0 +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# +# 0x8415c posix_spawn(rbx+0xe0, "/bin/sh", rdx, 0, rsp+0x60, [rax]) +# constraints: +# address rsp+0x78 is writable +# rsp & 0xf == 0 +# (u64)xmm0 == NULL || {(u64)xmm0, (u64)xmm1, [rsp+0x70], NULL} is a valid argv +# [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp +# rbx+0xe0 == NULL || writable: rbx+0xe0 +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# +# 0x84162 posix_spawn(rbx+0xe0, "/bin/sh", rdx, rcx, rsp+0x60, [rax]) +# constraints: +# address rsp+0x78 is writable +# rsp & 0xf == 0 +# (u64)xmm0 == NULL || {(u64)xmm0, (u64)(xmm0 >> 64), [rsp+0x70], NULL} is a valid argv +# [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp +# rbx+0xe0 == NULL || writable: rbx+0xe0 +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# rcx == NULL || (u16)[rcx] == NULL +# +# 0x84169 posix_spawn(rdi, "/bin/sh", rdx, rcx, rsp+0x60, [rax]) +# constraints: +# address rsp+0x78 is writable +# rsp & 0xf == 0 +# (u64)xmm0 == NULL || {(u64)xmm0, (u64)(xmm0 >> 64), [rsp+0x70], NULL} is a valid argv +# [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp +# rdi == NULL || writable: rdi +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# rcx == NULL || (u16)[rcx] == NULL +# +# 0x84170 posix_spawn(rdi, "/bin/sh", rdx, rcx, r8, [rax]) +# constraints: +# address rsp+0x78 is writable +# rsp & 0xf == 0 +# [r8] == NULL || r8 is a valid argv +# [[rax]] == NULL || [rax] == NULL || [rax] is a valid envp +# rdi == NULL || writable: rdi +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# rcx == NULL || (u16)[rcx] == NULL +# +# 0xe3afe execve("/bin/sh", r15, r12) +# constraints: +# [r15] == NULL || r15 == NULL || r15 is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp +# +# 0xe3b01 execve("/bin/sh", r15, rdx) +# constraints: +# [r15] == NULL || r15 == NULL || r15 is a valid argv +# [rdx] == NULL || rdx == NULL || rdx is a valid envp +# +# 0xe3b04 execve("/bin/sh", rsi, rdx) +# constraints: +# [rsi] == NULL || rsi == NULL || rsi is a valid argv +# [rdx] == NULL || rdx == NULL || rdx is a valid envp +# +# 0xe3cf3 execve("/bin/sh", r10, r12) +# constraints: +# address rbp-0x78 is writable +# [r10] == NULL || r10 == NULL || r10 is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp +# +# 0xe3cf6 execve("/bin/sh", r10, rdx) +# constraints: +# address rbp-0x78 is writable +# [r10] == NULL || r10 == NULL || r10 is a valid argv +# [rdx] == NULL || rdx == NULL || rdx is a valid envp # -# 0x13573e execl("/bin/sh", eax) +# 0xe3d62 execve("/bin/sh", rbp-0x50, r12) # constraints: +# address rbp-0x48 is writable +# r13 == NULL || {"/bin/sh", r13, NULL} is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp +# +# 0xe3d69 execve("/bin/sh", rbp-0x50, r12) +# constraints: +# address rbp-0x48 is writable +# rax == NULL || {rax, r13, NULL} is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp +# +# 0xe3d70 execve("/bin/sh", rbp-0x50, r12) +# constraints: +# address rbp-0x50 is writable +# rax == NULL || {rax, [rbp-0x48], NULL} is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp +# +# 0xe3da7 execve("/bin/sh", rbp-0x50, r12) +# constraints: +# address rbp-0x50 is writable +# [rbp-0x68] == NULL || {"/bin/sh", [rbp-0x68], NULL} is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp +# +# 0xe3db1 execve("/bin/sh", rbp-0x50, r12) +# constraints: +# address rbp-0x50 is writable +# rax == NULL || {rax, [rbp-0x68], NULL} is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp +# +# 0xe3db5 execve("/bin/sh", r10, r12) +# constraints: +# addresses r10+0x10, rbp-0x50 are writable +# [r10] == NULL || r10 == NULL || r10 is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp +# +# 0xe3dbd execve("/bin/sh", r10, r12) +# constraints: +# addresses r10+0x10, rbp-0x48 are writable +# [r10] == NULL || r10 == NULL || r10 is a valid argv +# [r12] == NULL || r12 == NULL || r12 is a valid envp +# +# 0x1077ca posix_spawn(rsp+0x64, "/bin/sh", [rsp+0x38], 0, rsp+0x70, [rsp+0xf0]) +# constraints: +# [rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv +# [[rsp+0xf0]] == NULL || [rsp+0xf0] == NULL || [rsp+0xf0] is a valid envp +# [rsp+0x38] == NULL || (s32)[[rsp+0x38]+0x4] <= 0 +# +# 0x1077d2 posix_spawn(rsp+0x64, "/bin/sh", [rsp+0x38], 0, rsp+0x70, r9) +# constraints: +# [rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv +# [r9] == NULL || r9 == NULL || r9 is a valid envp +# [rsp+0x38] == NULL || (s32)[[rsp+0x38]+0x4] <= 0 +# +# 0x1077d7 posix_spawn(rsp+0x64, "/bin/sh", rdx, 0, rsp+0x70, r9) +# constraints: +# [rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv +# [r9] == NULL || r9 == NULL || r9 is a valid envp +# rdx == NULL || (s32)[rdx+0x4] <= 0 +# +# 0x1077e1 posix_spawn(rdi, "/bin/sh", rdx, 0, r8, r9) +# constraints: +# [r8] == NULL || r8 is a valid argv +# [r9] == NULL || r9 == NULL || r9 is a valid envp +# rdi == NULL || writable: rdi +# rdx == NULL || (s32)[rdx+0x4] <= 0 + +``` + +#### Other Architectures + +##### i386 +```bash +$ one_gadget /lib32/libc.so.6 +# 0xc890b execve("/bin/sh", [ebp-0x2c], esi) +# constraints: +# address ebp-0x20 is writable # ebx is the GOT address of libc +# [[ebp-0x2c]] == NULL || [ebp-0x2c] == NULL || [ebp-0x2c] is a valid argv +# [esi] == NULL || esi == NULL || esi is a valid envp +# +# 0x1421b3 execl("/bin/sh", eax) +# constraints: +# ebp is the GOT address of libc # eax == NULL # -# 0x13573f execl("/bin/sh", [esp]) +# 0x1421b4 execl("/bin/sh", [esp]) # constraints: -# ebx is the GOT address of libc +# ebp is the GOT address of libc # [esp] == NULL ``` @@ -324,15 +523,15 @@ $ one_gadget ./spec/data/libc-2.19.so -s 'echo "offset ->"' ```ruby require 'one_gadget' OneGadget.gadgets(file: '/lib/x86_64-linux-gnu/libc.so.6') -#=> [324293, 324386, 1090444] +#=> [932606, 932609, 932612] # or in shorter way one_gadget('/lib/x86_64-linux-gnu/libc.so.6', level: 1) -#=> [324293, 324386, 939679, 940120, 940127, 940131, 1090444, 1090456] +#=> [335355, 335362, 335369, 335376, 335381, 335397, 335402, 335405, 335410, 540981, 540988, 540995, 540998, 541003, 541008, 541020, 541026, 541033, 541040, 932606, 932609, 932612, 933107, 933110, 933218, 933225, 933232, 933287, 933297, 933301, 933309, 1079242, 1079250, 1079255, 1079265] # from build id one_gadget('b417c0ba7cc5cf06d1d1bed6652cedb9253c60d0') -#=> [324293, 324386, 1090444] +#=> [324286, 324293, 324386, 1090444] ``` @@ -343,7 +542,7 @@ def one_gadget(filename): return [int(i) for i in subprocess.check_output(['one_gadget', '--raw', filename]).decode().split(' ')] one_gadget('/lib/x86_64-linux-gnu/libc.so.6') -#=> [324293, 324386, 1090444] +#=> [932606, 932609, 932612] ``` diff --git a/lib/one_gadget/cli.rb b/lib/one_gadget/cli.rb index 030ed6a9..d4ae7c25 100644 --- a/lib/one_gadget/cli.rb +++ b/lib/one_gadget/cli.rb @@ -49,9 +49,9 @@ def work(argv) return show(parser.help) && false unless build_id || libc_file gadgets = if build_id - OneGadget.gadgets(build_id: build_id, details: true, level: level) + OneGadget.gadgets(build_id:, details: true, level:) else # libc_file - OneGadget.gadgets(file: libc_file, details: true, force_file: @options[:force_file], level: level) + OneGadget.gadgets(file: libc_file, details: true, force_file: @options[:force_file], level:) end gadgets.each { |g| g.base = @options[:base] } handle_gadgets(gadgets, libc_file) @@ -119,8 +119,8 @@ def parser @options[:level] = l end - opts.on('-n', '--near FUNCTIONS/FILE', 'Order gadgets by their distance to the given functions'\ - ' or to the GOT functions of the given file.') do |n| + opts.on('-n', '--near FUNCTIONS/FILE', 'Order gadgets by their distance to the given functions ' \ + 'or to the GOT functions of the given file.') do |n| @options[:near] = n end diff --git a/lib/one_gadget/emulators/aarch64.rb b/lib/one_gadget/emulators/aarch64.rb index a75856db..4fafc230 100644 --- a/lib/one_gadget/emulators/aarch64.rb +++ b/lib/one_gadget/emulators/aarch64.rb @@ -18,8 +18,8 @@ def initialize # @see OneGadget::Emulators::X86#process! def process!(cmd) - inst, args = parse(cmd.gsub(/#-?(0x)?[0-9a-f]+/) { |v| v[1..-1] }) - sym = "inst_#{inst.inst}".to_sym + inst, args = parse(cmd.gsub(/#-?(0x)?[0-9a-f]+/) { |v| v[1..] }) + sym = :"inst_#{inst.inst}" __send__(sym, *args) != :fail end diff --git a/lib/one_gadget/emulators/instruction.rb b/lib/one_gadget/emulators/instruction.rb index 76ac73f0..f0d19192 100644 --- a/lib/one_gadget/emulators/instruction.rb +++ b/lib/one_gadget/emulators/instruction.rb @@ -31,7 +31,7 @@ def fetch_args(cmd) idx = cmd.index(inst) cmd = cmd[0...cmd.rindex('//')] if cmd.rindex('//') cmd = cmd[0...cmd.rindex('#')] if cmd.rindex('#') - args = parse_args(cmd[idx + inst.size..-1]) + args = parse_args(cmd[idx + inst.size..]) unless argc.include?(args.size) raise OneGadget::Error::InstructionArgumentError, "Incorrect argument number in #{cmd}, expect: #{argc}" end diff --git a/lib/one_gadget/emulators/lambda.rb b/lib/one_gadget/emulators/lambda.rb index 8d85a29a..572a8119 100644 --- a/lib/one_gadget/emulators/lambda.rb +++ b/lib/one_gadget/emulators/lambda.rb @@ -43,7 +43,7 @@ def +(other) # @param [Numeric] other Value to substract. # @return [Lambda] The result. def -(other) - self.+(-other) + self + -other end # Increase dereference count by 1. @@ -123,8 +123,8 @@ def parse(argument, predefined: {}) # nested [] if arg[0] == '[' ridx = arg.rindex(']') - immi = parse(arg[(ridx + 1)..-1]) - lm = parse(arg[1...ridx], predefined: predefined).deref + immi = parse(arg[(ridx + 1)..]) + lm = parse(arg[1...ridx], predefined:).deref lm += immi unless immi.zero? return lm end diff --git a/lib/one_gadget/emulators/processor.rb b/lib/one_gadget/emulators/processor.rb index 38c36cc0..d8ba40c4 100644 --- a/lib/one_gadget/emulators/processor.rb +++ b/lib/one_gadget/emulators/processor.rb @@ -19,7 +19,7 @@ class Processor # @param [String] sp # The stack register. def initialize(registers, sp) - @registers = registers.map { |reg| [reg, to_lambda(reg)] }.to_h + @registers = registers.to_h { |reg| [reg, to_lambda(reg)] } @sp = sp @constraints = [] @sp_based_stack = Hash.new do |h, k| diff --git a/lib/one_gadget/emulators/x86.rb b/lib/one_gadget/emulators/x86.rb index 6512369d..eb65f79a 100644 --- a/lib/one_gadget/emulators/x86.rb +++ b/lib/one_gadget/emulators/x86.rb @@ -36,7 +36,7 @@ def process!(cmd) # return registers[pc] = args[0] if inst.inst == 'call' return true if inst.inst == 'jmp' # believe the fetcher has handled jmp. - sym = "inst_#{inst.inst}".to_sym + sym = :"inst_#{inst.inst}" __send__(sym, *args) != :fail end diff --git a/lib/one_gadget/fetcher.rb b/lib/one_gadget/fetcher.rb index bc51c738..bc9c1176 100644 --- a/lib/one_gadget/fetcher.rb +++ b/lib/one_gadget/fetcher.rb @@ -20,7 +20,7 @@ module ClassMethods # +nil+ is returned if cannot find target id in database. def from_build_id(build_id, remote: true) OneGadget::Helper.verify_build_id!(build_id) - OneGadget::Gadget.builds(build_id, remote: remote) + OneGadget::Gadget.builds(build_id, remote:) end # Fetch one-gadget offsets from file. diff --git a/lib/one_gadget/fetchers/base.rb b/lib/one_gadget/fetchers/base.rb index 79163703..1f43a724 100644 --- a/lib/one_gadget/fetchers/base.rb +++ b/lib/one_gadget/fetchers/base.rb @@ -28,7 +28,7 @@ def find # use processor to find which can lead to a valid one-gadget call. gadgets = [] (lines.size - 2).downto(0) do |i| - processor = emulate(lines[i..-1]) + processor = emulate(lines[i..]) options = resolve(processor) next if options.nil? # impossible to be a gadget @@ -48,7 +48,7 @@ def find # True for valid. # @return [Array] # Each +String+ returned is multi-lines of assembly code. - def candidates(&block) + def candidates(&) call_regexp = "#{call_str}.*<(exec[^+]*|posix_spawn[^+]*)>$" cands = [] `#{@objdump.command}|grep -E '#{call_regexp}' -B 30`.split('--').each do |cand| @@ -63,7 +63,7 @@ def candidates(&block) end # remove all jmps cands = slice_prefix(cands, &method(:branch?)) - cands.select!(&block) if block_given? + cands.select!(&) if block_given? cands end @@ -81,7 +81,8 @@ def resolve(processor) call = processor.registers[processor.pc].to_s return resolve_posix_spawn(processor) if call.include?('posix_spawn') return resolve_execve(processor) if call.include?('execve') - return resolve_execl(processor) if call.include?('execl') + + resolve_execl(processor) if call.include?('execl') end def resolve_execve(processor) @@ -110,7 +111,7 @@ def resolve_execve_args(processor, arg0, arg1, arg2, allow_null_argv: true) envp = arg2 end - { constraints: cons, envp: envp } + { constraints: cons, envp: } end def check_argv(processor, arg, allow_null) @@ -282,7 +283,7 @@ def slice_prefix(cands, &block) cands.map do |cand| lines = cand.lines to_rm = lines[0...-1].rindex(&block) - lines = lines[to_rm + 1..-1] unless to_rm.nil? + lines = lines[to_rm + 1..] unless to_rm.nil? lines.join end end diff --git a/lib/one_gadget/gadget.rb b/lib/one_gadget/gadget.rb index 974d7e27..3b416358 100644 --- a/lib/one_gadget/gadget.rb +++ b/lib/one_gadget/gadget.rb @@ -112,7 +112,7 @@ def merge_constraints w_cons, normal = constraints.partition { |c| c.start_with?(key) } return normal if w_cons.empty? - w_cons.map! { |c| c[key.size..-1] } + w_cons.map! { |c| c[key.size..] } ["address#{w_cons.size > 1 ? 'es' : ''} #{w_cons.join(', ')} #{w_cons.size > 1 ? 'are' : 'is'} writable"] + normal end @@ -161,7 +161,7 @@ def builds(build_id, remote: true) def builds_info(build_id) raise Error::ArgumentError, "Invalid BuildID #{build_id.inspect}" if build_id =~ /[^0-9a-f]/ - files = Dir.glob(File.join(BUILDS_PATH, "*-#{build_id}*.rb")).sort + files = Dir.glob(File.join(BUILDS_PATH, "*-#{build_id}*.rb")) return OneGadget::Logger.not_found(build_id) && nil if files.empty? if files.size > 1 @@ -189,7 +189,7 @@ def add(build_id, offset, **options) def find_build(id) return BUILDS[id] if BUILDS.key?(id) - Dir.glob(File.join(BUILDS_PATH, "*-#{id}.rb")).sort.each do |dic| + Dir.glob(File.join(BUILDS_PATH, "*-#{id}.rb")).each do |dic| require dic end BUILDS[id] if BUILDS.key?(id) diff --git a/lib/one_gadget/helper.rb b/lib/one_gadget/helper.rb index d57674be..5049e07e 100644 --- a/lib/one_gadget/helper.rb +++ b/lib/one_gadget/helper.rb @@ -13,7 +13,7 @@ module OneGadget # Define some helpful methods here. module Helper # Format of build-id, 40 hex numbers. - BUILD_ID_FORMAT = /[0-9a-f]{40}/.freeze + BUILD_ID_FORMAT = /[0-9a-f]{40}/ module_function @@ -35,7 +35,7 @@ def verify_build_id!(build_id) # @return [Array] # Lines of comments. def comments_of_file(file) - File.readlines(file).map { |s| s[2..-1].rstrip if s.start_with?('# ') }.compact + File.readlines(file).map { |s| s[2..].rstrip if s.start_with?('# ') }.compact end # Get absolute path from relative path. Support symlink. diff --git a/lib/one_gadget/update.rb b/lib/one_gadget/update.rb index a8a08ecc..b8a73c68 100644 --- a/lib/one_gadget/update.rb +++ b/lib/one_gadget/update.rb @@ -24,14 +24,14 @@ def check! FileUtils.touch(cache_file) OneGadget::Logger.info("Checking for new versions of OneGadget\n" \ "To disable this functionality, do\n$ echo never > #{CACHE_FILE}\n\n") - latest = Helper.latest_tag[1..-1] # remove 'v' + latest = Helper.latest_tag[1..] # remove 'v' if Gem::Version.new(latest) <= Gem::Version.new(OneGadget::VERSION) return OneGadget::Logger.info("You have the latest version of OneGadget (#{latest})!\n\n") end # show update message msg = format('A newer version of OneGadget is available (%s --> %s).', OneGadget::VERSION, latest) - OneGadget::Logger.ask_update(msg: msg) + OneGadget::Logger.ask_update(msg:) end private diff --git a/one_gadget.gemspec b/one_gadget.gemspec index 47c78a14..1938bbbd 100644 --- a/one_gadget.gemspec +++ b/one_gadget.gemspec @@ -9,7 +9,7 @@ require 'one_gadget/version' Gem::Specification.new do |s| s.name = 'one_gadget' - s.version = ::OneGadget::VERSION + s.version = OneGadget::VERSION s.summary = 'one_gadget' s.description = <<-EOS When playing ctf pwn challenges we usually needs the one-gadget of execve('/bin/sh', NULL, NULL). @@ -32,9 +32,9 @@ Gem::Specification.new do |s| 'source_code_uri' => 'https://github.com/david942j/one_gadget' } - s.required_ruby_version = '>= 2.4' + s.required_ruby_version = '>= 3.1' - s.add_runtime_dependency 'elftools', '>= 1.0.2', '< 1.2.0' + s.add_dependency 'elftools', '>= 1.0.2', '< 1.2.0' s.add_development_dependency 'rake', '~> 13.0' s.add_development_dependency 'rspec', '~> 3.7' diff --git a/spec/emulators/i386_spec.rb b/spec/emulators/i386_spec.rb index 303ea098..9fa3132d 100644 --- a/spec/emulators/i386_spec.rb +++ b/spec/emulators/i386_spec.rb @@ -62,7 +62,7 @@ end it 'libc-2.19' do - gadget = <<-'EOS' + gadget = <<-EOS 64c60: mov DWORD PTR [esp+0x8],eax 64c64: lea eax,[ebx-0x4956f] 64c6a: mov DWORD PTR [esp+0x4],eax diff --git a/spec/emulators/instruction_spec.rb b/spec/emulators/instruction_spec.rb index d0d5105b..5471d22d 100644 --- a/spec/emulators/instruction_spec.rb +++ b/spec/emulators/instruction_spec.rb @@ -18,20 +18,20 @@ end it 'fetch_args' do - expect(@mov.fetch_args(<<-'EOS')).to eq ['rax', '[rip+0x2c16b4]'] + expect(@mov.fetch_args(<<-EOS)).to eq ['rax', '[rip+0x2c16b4]'] d67e5: 48 8b 05 b4 16 2c 00 mov rax,QWORD PTR [rip+0x2c16b4] # 397ea0 <_DYNAMIC+0x340> EOS - expect(@mov.fetch_args(<<-'EOS')).to eq ['rdx', '[rax]'] + expect(@mov.fetch_args(<<-EOS)).to eq ['rdx', '[rax]'] d67f8: 48 8b 10 mov rdx,QWORD PTR [rax] EOS expect { @mov.fetch_args('mov a, b, c') }.to raise_error(OneGadget::Error::InstructionArgumentError) - expect(@lea.fetch_args(<<-'EOS')).to eq ['rsi', '[rsp+0x70]'] + expect(@lea.fetch_args(<<-EOS)).to eq ['rsi', '[rsp+0x70]'] d67ec: 48 8d 74 24 70 lea rsi,[rsp+0x70] EOS - expect(@lea.fetch_args(<<-'EOS')).to eq ['rdi', '[rip+0x8ab61]'] + expect(@lea.fetch_args(<<-EOS)).to eq ['rdi', '[rip+0x8ab61]'] d67f1: 48 8d 3d 61 ab 08 00 lea rdi,[rip+0x8ab61] # 161359 <_nl_POSIX_name+0x154> EOS - expect(@call.fetch_args(<<-'EOS')).to eq ['b8470 '] + expect(@call.fetch_args(<<-EOS)).to eq ['b8470 '] d67fb: e8 70 1c fe ff call b8470 EOS end diff --git a/spec/emulators/lambda_spec.rb b/spec/emulators/lambda_spec.rb index 78f64e1e..d1bf4d82 100644 --- a/spec/emulators/lambda_spec.rb +++ b/spec/emulators/lambda_spec.rb @@ -50,7 +50,7 @@ expect(described_class.parse('0xabc123')).to be 0xabc123 predefined = { 'rsp' => described_class.new('rsp') + 0x10 } - expect(described_class.parse('rsp+0x20', predefined: predefined).to_s).to eq 'rsp+0x30' + expect(described_class.parse('rsp+0x20', predefined:).to_s).to eq 'rsp+0x30' # Nested [] expect(described_class.parse('[[rsp+0x33]]').to_s).to eq '[[rsp+0x33]]' diff --git a/spec/helper_spec.rb b/spec/helper_spec.rb index 90092a85..5c17885f 100644 --- a/spec/helper_spec.rb +++ b/spec/helper_spec.rb @@ -33,9 +33,9 @@ it 'url_request' do val = :val - expect { hook_logger { val = described_class.url_request('oao') } }.to output(include(<<-EOS)).to_stdout -[OneGadget] undefined method `request_uri' for # - EOS + expect do + hook_logger { val = described_class.url_request('oao') } + end.to output(include('[OneGadget] undefined method')).to_stdout expect(val).to be_nil end diff --git a/tasks/builds/generate.rake b/tasks/builds/generate.rake index fd4a65c3..1d888231 100644 --- a/tasks/builds/generate.rake +++ b/tasks/builds/generate.rake @@ -77,12 +77,12 @@ namespace :builds do st = str.index('GNU C Library') return nil if st.nil? - len = str[st..-1].index("\x00") + len = str[st..].index("\x00") return nil if len.nil? fname = filename.sub('../libcdb', 'https://gitlab.com/david942j/libcdb/blob/master') { - build_id: build_id, + build_id:, info: "#{fname}\n\n#{arch}\n\n#{str[st, len]}" } rescue ELFTools::ELFError, EOFError # corrupted elf file diff --git a/tasks/builds/list.rake b/tasks/builds/list.rake index 629f79ff..e25de553 100644 --- a/tasks/builds/list.rake +++ b/tasks/builds/list.rake @@ -5,7 +5,7 @@ namespace :builds do task :list do rd = File.join(__dir__, '..', '..') f = File.open(File.join(rd, 'builds_list'), 'w') - Dir.glob(File.join(rd, 'lib', 'one_gadget', 'builds', '*.rb')).sort.each do |file| + Dir.glob(File.join(rd, 'lib', 'one_gadget', 'builds', '*.rb')).each do |file| f.puts File.basename(file, '.rb') end f.close