Skip to content

Instantly share code, notes, and snippets.

@gteissier
Created June 3, 2020 13:23
Show Gist options
  • Save gteissier/8dfd606e2fafa4ed2495fe748c8a2a19 to your computer and use it in GitHub Desktop.
Save gteissier/8dfd606e2fafa4ed2495fe748c8a2a19 to your computer and use it in GitHub Desktop.
gdb Python script that adds root-single command to elevate a process given by the name of its executable
import gdb
import re
from collections import namedtuple
DETAILS = {
# API 24 playstore
# API 25 playstore
'3.10.0+': (0xC0887D20, 0xC092138C, 316, 0xC0A7754C, 4),
# API 26 playstore
'3.18.56+': (0xC09F262A, 0xC0AD4208, 380, 0xC0C3428C, 4),
# API 27 playstore
'3.18.91+': (0xC09FC478, 0xC0AEE208, 380, 0xC0C4F28C, 4),
# API 28 playstore
'4.4.124+': (0xFFFFFFFF80BF5613, 0xFFFFFFFF80E0FBD8, 688, 0xFFFFFFFF8118CFD0, 8),
# API 29 playstore
'4.14.112+': (0xFFFFFFFF8100E970, 0xFFFFFFFF81415868, 680, 0xFFFFFFFF8169CDC8, 8),
}
Task = namedtuple('Task', 'addr real_cred comm')
class Rooter:
def __init__(self):
for version in DETAILS:
(version_addr, init_task_tasks, tasks_to_comm, selinux_enforcing, address_size) = DETAILS[version]
version_str = self.cstring(version_addr)
if version_str.startswith(version):
print('[+] kernel version confirmed to be %s' % version)
self.version = version
self.init_task_tasks = init_task_tasks
self.tasks_to_comm = tasks_to_comm
self.selinux_enforcing = selinux_enforcing
self.address_size = address_size
if self.address_size == 4: self.dereference_fmt = 'w'
elif self.address_size == 8: self.dereference_fmt = 'g'
return
raise Exception("kernel version has not been successfully identified")
def cstring(self, addr):
output = gdb.execute('x/s 0x%x' % (addr), to_string=True)
if 'error' in output: return ''
m = re.search(r'"(.*)"', output)
if not m: return ''
return m.group(1)
def dereference(self, addr):
output = gdb.execute('x/%sx 0x%x' % (self.dereference_fmt, addr), to_string=True)
if 'error' in output: return -1
m = re.search(r'\t(0x[a-fA-F0-9]+)', output)
if not m: return -1
return int(m.group(1), 0)
def get_tasks(self):
if self.tasks_to_comm == 0:
current_task = self.init_task_tasks
output = gdb.execute('find 0x%x,+1024,"swapper/0"' % (current_task), to_string=True)
print('[+] output = %r' % output)
m = re.search(r'(0x[a-fA-F0-9]+)\n', output, re.S)
if not m:
print('[!] there shall be something wrong, "swapper/0" could not be found near init_task address')
return []
found_comm = int(m.group(1), 0)
found_distance = found_comm - self.init_task_tasks
print('[+] computed tasks_to_comm: 0x%x - 0x%x = %d' % (found_comm, self.init_task_tasks, found_distance))
self.tasks_to_comm = found_distance
tasks = []
current_task = self.init_task_tasks
while True:
comm = self.cstring(current_task + self.tasks_to_comm)
real_cred = self.dereference(current_task + self.tasks_to_comm - 2*self.address_size)
next_task = self.dereference(current_task)
tasks.append(Task(current_task, real_cred, comm))
if next_task == self.init_task_tasks:
break
current_task = next_task
return tasks
def change_uids(self, task, uid):
for i in range(9):
uid_addr = task.real_cred + 4 + 4*i
gdb.execute('set *(unsigned int *) 0x%x = 0' % uid_addr)
def change_capabilities(self, task, caps):
for i in range(3):
cap_addr = task.real_cred + 0x30 + 8*i
gdb.execute('set *(unsigned long *) 0x%x = 0x%x' % (cap_addr, caps))
def disable_selinux(self):
gdb.execute('set *(unsigned int *) 0x%x = 0' % (self.selinux_enforcing))
class RootSingle(gdb.Command):
def __init__(self):
super().__init__('root-single', gdb.COMMAND_USER)
def invoke(self, args, tty):
args = gdb.string_to_argv(args)
if len(args) == 1:
name = args[0]
else:
print('usage: root-single <process name to elevate>')
return
rooter = Rooter()
tasks = rooter.get_tasks()
found_task = False
for task in tasks:
if name in task.comm:
print('[+] found matching task at 0x%x' % (task.addr))
rooter.change_uids(task, 0)
print('[+] changed uids to 0')
rooter.change_capabilities(task, 0x3fffffffff)
print('[+] changed caps to 0x3fffffffff')
rooter.disable_selinux()
print('[+] changed selinux to permissive')
found_task = True
if not found_task:
print('[!] no task was found containing name "%s", please double check the task exists' % name)
RootSingle()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment