Inf0 - buuctf https://dirtycow.cn/tag/buuctf/ NewStarCTF 2023 Week2 reverse easy_enc https://dirtycow.cn/173.html 2023-11-02T20:30:00+08:00 思路:直接爆破exp:#include <stdio.h> #include <string.h> int main() { int enc[] = { 0xE8, 0x80, 0x84, 0x08, 0x18, 0x3C, 0x78, 0x68, 0x00, 0x70, 0x7C, 0x94, 0xC8, 0xE0, 0x10, 0xEC, 0xB4, 0xAC, 0x68, 0xA8, 0x0C, 0x1C, 0x90, 0xCC, 0x54, 0x3C, 0x14, 0xDC, 0x30 }; char key[] = "NewStarCTF"; for(int i =0; i < 29; i++) { for(int j = 33; j < 127; j++) { int tmp = j; if(tmp >= 'A' && tmp <= 'Z') { tmp = (tmp - 52) % 26 + 65; } else if(tmp >= '0' && tmp <= '9') { tmp = (tmp - 45) % 10 + 48; } else if(tmp >= 'a' && tmp <= 'z') { tmp = (tmp - 89) % 26 + 97; } tmp += key[i % strlen(key)]; tmp = ~tmp; tmp = (unsigned char)(tmp * 52); if(tmp == enc[i]) { if((j >= 'A' && j <= 'Z') || (j >= 'a' && j <= 'z')) { printf("%c", j); break; } } } } return 0; }flag:BruteForceIsAGoodwaytoGetFlag NewStarCTF 2023 Week2 reverse Random_1 https://dirtycow.cn/172.html 2023-11-02T18:20:00+08:00 思路:思路就是爆破要注意windows的srand()函数和Linux的srand()函数不一样,要放在linux中运行exp:#include <stdio.h> #include <stdlib.h> int main() { unsigned char enc[] = { 0xEE, 0xE6, 0xD7, 0xB2, 0x8A, 0xAB, 0x13, 0x35, 0x02, 0x7B, 0xC9, 0xB9, 0x9C, 0xBA, 0xED, 0x2E, 0xBD, 0x4F, 0xFA, 0xEE, 0xC8, 0xF8, 0xE4, 0x16, 0x82, 0x63, 0x3B, 0x98, 0xF4, 0x14, 0x30, 0x38, 0x07, 0x36, 0x84, 0x3D, 0x0C, 0x36, 0x32, 0xEA, 0x55, 0xA6 }; unsigned char Table[] = { 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 }; srand(0x7261745377654E); int v4 = 0; int v3 = 0; char flag[43] = {0}; for(int j = 0; j < 42; j++ ) { v4 = rand(); for(int i = 32; i < 127; i++) { v3 = i; if(enc[j] == Table[(16 * ((v3 + v4 % 255) >> 4) + 15) & (v3 + v4 % 255)]) { flag[j] = i; break; } } } printf("%s", flag); return 0; }flag:flag{B8452786-DD8E-412C-E355-2B6F27DAB5F9} NewStarCTF 2023 SMC https://dirtycow.cn/170.html 2023-10-25T17:48:00+08:00 思路:拿到题目,先使用exeinfo查壳image-20231025165019875.png程序是无壳32位使用ida打开,查看伪代码image-20231025165121623.png大概过一遍程序将用户输入保存在unk_4033D4之后有个反调试,然后调用了sub_401042()函数接下来是一个判断,判断flag是否正确,但是ida没有识别出来这个函数,应该是被加密了跟进sub_401042()函数查看image-20231025165803500.png这个函数对数组byte_403040进行了操作,这个数组就是判断flag时调用的函数我们只要动调到sub_401042()函数执行完就可以看到验证flag的函数因为程序有反调试,我们在检测反调试的地方下个断点image-20231025172019455.png调试启动!!!输入flag之后程序停在了跳转这边image-20231025172126171.pngjz是判断zf标志位来跳转的image-20231025172541644.png我们只要修改zf标志位就能控制跳转,将zf改成1,在判断flag的的地方下个断点,继续运行image-20231025173030609.png按f7于运行一步,双击进入byte_403040image-20231025173250544.pngida已经识别出指令了,在函数头按P创建函数,再按f5查看伪代码image-20231025173341591.png现在已经能看到flag的验证函数了用户输入的数据异或0x11再加5等于加密字符串,我们只要将加密flag反正运算一下就能得到flag接下来写expexp:双击进入unk_403020,选中shift+e就能提取加密flag的数据image-20231025174343190.pngenc = [ 0x7C, 0x82, 0x75, 0x7B, 0x6F, 0x47, 0x61, 0x57, 0x53, 0x25, 0x47, 0x53, 0x25, 0x84, 0x6A, 0x27, 0x68, 0x27, 0x67, 0x6A, 0x7D, 0x84, 0x7B, 0x35, 0x35, 0x48, 0x25, 0x7B, 0x7E, 0x6A, 0x33, 0x71 ] flag = '' for i in range(32): flag += chr((enc[i] - 5) ^ 0x11) print(flag)flag:flag{SMC_1S_1nt3r3sting!!R1ght?} NewStarCTF 2023 Week2 Petals https://dirtycow.cn/157.html 2023-10-24T22:00:00+08:00 思路:拿到题目,使用exeinfo查看image-20231024210806544.png程序是64位的elf拖入ida查看, 找到主函数按f5查看伪代码image-20231024211006264.png程序读取了用户输入的字符串保存在byte_4080 ,将其重命名成input又将input的长度赋值给了v4,将v4重命名成len继续我往下看image-20231024211353736.png有个if判断了input的长度是否等于25,不等于则退出程序input和len别传入loc_1209,跟进去查看image-20231024211722721.png发现一片红的,ida没有将这个函数识别出来,应该是程序添加了花指令,往下翻image-20231024212124145.png在这边看到了两个指令jz和jnzjz代表zf标志位为0时跳转jnz代表zf标志位不为0时跳转这两个指令都将跳转到13b0+1这个地址,而这个地址别ida识别成了指令光标定位到这个地址,按下键盘上的U,取消定义image-20231024213316861.png再选中c7,按下键盘上的C,将其转换成代码image-20231024213409565.png这时候地址13b1就出来了,再将上面的E8给nop掉,因为程序经过jz和jnz会跳转到13b1这个地址,13b0这个地址并不会别执行,所以可以直接nopimage-20231024213750268.pngimage-20231024213808277.png选中函数头按下键盘上的P创建函数,再按f5, ida成功识别出来这个函数查看这个函数image-20231024214013565.png程序先初始化了v5,将~(i^a2)的值存入的v5 ,这里的a2是len第二个循环翻译过来就是for(j = 0; len > j; j++) { input[j] = v5[input[j]] }这里将input的值作为v5的下标赋值给input继续往下看,进入sub_160C函数查看image-20231024215111632.pnga1 a2 a3 分别是input &unk_4020 len双击&unk_4020 查看image-20231024215232379.png这就是加密的flag这个函数将修改后的input和加密后的flag进行比较看到这里已经可以逆向推算出flag了我们只要在v5中找加密的flag,取它的下标就是flagexp:#include <stdio.h> int main() { unsigned char enc[] = { 0xD0, 0xD0, 0x85, 0x85, 0x80, 0x80, 0xC5, 0x8A, 0x93, 0x89, 0x92, 0x8F, 0x87, 0x88, 0x9F, 0x8F, 0xC5, 0x84, 0xD6, 0xD1, 0xD2, 0x82, 0xD3, 0xDE, 0x87 }; char table[256] = {0}; for(int i =0; i <= 255; i++) { table[i] = ~(i^25); } char flag[26] = {0}; for(int j = 0; 25 >j; j++) { for(int k = 0; k <= 255; k++) { if(enc[j] == table[k]) { flag[j] = k; } } } printf("%s", flag); return 0; }运行结果C:\Users\777\Desktop\reverse\NewStarCTF 2023 公开赛道\2>gcc Petals.c C:\Users\777\Desktop\reverse\NewStarCTF 2023 公开赛道\2>a 66ccff#luotianyi#b074d58aflag:flag{d780c9b2d2aa9d40010a753bc15770de} BUUCTF [0CTF 2016]piapiapia https://dirtycow.cn/78.html 2023-10-23T20:17:00+08:00 知识点:1.php的序列化和反序列化:序列化就是把对象或者变量转化为字符串从而便于存储和传输反序列化就是把序列化的字符串转化为原来的对象或者变量序列化例子:<?php class Person{ public $name = "user"; private $age = 18; protected $num = "11111111"; function test(){ $this->name = "user1"; echo $this->$name; } } $test = new Person(); echo serialize($test); ?>输出内容:O:6:"Person":3:{s:4:"name";s:4:"user";s:11:"Personage";i:18;s:6:"*num";s:8:"11111111";}对象类型 : 对象长度 : "对象名称" : 类里面的变量个数 : {变量类型 : 长度 : 变量名称; 值类型 : 变量值长度 : 变量值; ......}O是指一个对象,6是Person的长度,3是有三个属性,{}里面是属性的内容; 第一个s是name的类型,4是name长度,第二个s是变量name值的类型,第二个4是"user"的长度,"user" 是变量name的值 以此类推。注意类里面的方法不会参加序列化。需要注意的是变量受到不同修饰符(public,private,protected)修饰进行序列化时,序列化后变量的长度和名称会发生变化。使用public修饰进行序列化后,变量$name的长度为4,正常输出。使用private修饰进行序列化后,会在变量$age前面加上类的名称,在这里是Person,并且长度会比正常大小多2个字节,也就是6+3+2=11。使用protected修饰进行序列化后,会在变量$team_group前面加上*,并且长度会比正常大小多3个字节,也就是3+3=6。通过对比发现,在受保护的成员前都多了两个字节,受保护的成员在序列化时规则:  1. 受Private修饰的私有成员,序列化时: \x00 + [私有成员所在类名] + \x00 [变量名]  2. 受Protected修饰的成员,序列化时:\x00 + * + \x00 + [变量名]  其中,"\x00"代表ASCII为0的值,即空字节," * " 必不可少。反序列化:<?php class Person{ public $name = "user"; private $age = 18; protected $num = "11111111"; function test(){ $this->name = "user1"; echo $this->name . "\n"; } } $test = new Person(); echo serialize($test); echo "\n"; $str = serialize($test); $test2 = unserialize($str); $test2->test(); var_dump($test2); ?>输出内容:O:6:"Person":3:{s:4:"name";s:4:"user";s:11:"Personage";i:18;s:6:"*num";s:8:"11111111";} user1 object(Person)#2 (3) { ["name"]=> string(5) "user1" ["age":"Person":private]=> int(18) ["num":protected]=> string(8) "11111111" }使用反序列化函数反序列化序列化后字符串$test2可以调用test方法用var_dump 对象,可以查看对象内部结构2.php反序列化字符逃逸什么事字符逃逸,从字面意思上看,就是一些字符被丢弃。序列化后的字符串进行反序列化操作时,会以{}两个花括号进行分界线,花括号外的内容不会被反序列化。例子: <?php class people{ public $name = 'aaa'; public $sex = 'boy'; } $a = new people(); print_r(serialize($a)); echo "\n"; $str='O:6:"people":2:{s:4:"name";s:3:"aaa";s:3:"sex";s:3:"boy";}123'; var_dump(unserialize($str)); ?>输出结果O:6:"people":2:{s:4:"name";s:3:"aaa";s:3:"sex";s:3:"boy";} object(people)#2 (2) { ["name"]=> string(3) "aaa" ["sex"]=> string(3) "boy" }在序列化字符串后面添加123PHP不会报错,并且也不会输出123.说明{}是字符串反序列化时的分界符。当然,在进行反序列化时,是从左到右读取。读取多少取决于s后面的字符长度。比如当我们将数字改成5<?php $str='O:6:"people":2:{s:5:"name";s:3:"aaa";s:3:"sex";s:3:"boy";}'; var_dump(unserialize($str)); ?>输出结果bool(false)此时在读取name时,它会将闭合的双引号也读取在内,而需要闭合字符串的双引号被当作字符串处理,这时就会导致语法错误而报错。一般触发字符逃逸的前提是这个替换函数str_replace,能将字符串的长度改变。其主要原理就是运用闭合的思想。字符逃逸主要有两种,一种是字符增多,一种是字符减少。字符增多<?php class A{ public $name = 'aaaaaaaaaaaaaaaaaaaaaaaaaa";s:6:"passwd";s:3:"123";}'; public $passwd = '1234'; } $ss = new A(); $str = serialize($ss); //echo $str; function filter($str){ return str_replace('aa','bbbb',$str); } $tt = filter($str); echo $tt; $qq = unserialize($tt); var_dump($qq); ?>大家可能会有一个疑惑?为什么要有这个str_replace函数,我认为可能是想过滤掉用户输入的恶意代码,防止恶意代码执行恶意命令。(主要还是unserialize函数的参数可控)。这段代码主要目的就是间接修改passwd的值";s:6:"passwd";s:3:"123";}输出结果:O:1:"A":2:{s:4:"name";s:52:"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";s:6:"passwd";s:3:"123";}";s:6:"passwd";s:4:"1234";}object(A)#2 (2) { ["name"]=> string(52) "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" ["passwd"]=> string(3) "123" }这个字符串一共有26字符。我们想要让这段字符串进行反序列化,而;}正好将前面闭合,从而将字符串";s:6:"passwd";s:4:"1234";}逃逸出去。这样就可以间接修改passwd的值了。回过头看代码,序列化字符串中将aa替换为bbbb,这样就多出两个字符。以此类推,我们输入13个aa,就会多出26个字符,正好达到name的字符串长度,成功将s:6:"passwd";s:3:"123";}反序列化这样就将passwd的值改为123字符减少<?php class A{ public $name = 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";s:6:"passwd";s:3:"123";}'; public $passwd = '1234";s:6:"passwd";s:3:"123'; } $ss = new A(); $str = serialize($ss); //echo $str; function filter($str){ return str_replace('bb','a',$str); } $tt = filter($str); echo $tt; $qq = unserialize($tt); var_dump($qq); ?>同样道理,我们要将s:6:"passwd";s:3:"123成功反序列化,那么就要把";s:6:"passwd";s:27:"1234这段字符串给吃掉。这段字符串一共有25个字符,则我们在name中输入25个bO:1:"A":2:{s:4:"name";s:52:"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";s:6:"passwd";s:3:"123";}";s:6:"passwd";s:4:"1234";}object(A)#2 (2) { ["name"]=> string(52) "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" ["passwd"]=> string(3) "123" }总结:字符逃逸的主要原理就是闭合,和sql注入类似,只不过它判断的是字符串的长度。输入恰好的字符串长度,让无用的部分字符逃逸或吞掉,从而达到我们想要的目的解题思路:web题信息收集很重要!!!没有思路就去扫目录!!!打开题目,发现主页是个登录页面经过各种测试,排除了sql注入的漏洞的可能image-20221011195102510.png通过目录扫描,发现网站根目录存在www.zip将其下载下来进行代码审计//profile.php <?php require_once('class.php'); if($_SESSION['username'] == null) { die('Login First'); } $username = $_SESSION['username']; $profile=$user->show_profile($username); if($profile == null) { header('Location: update.php'); } else { $profile = unserialize($profile); $phone = $profile['phone']; $email = $profile['email']; $nickname = $profile['nickname']; $photo = base64_encode(file_get_contents($profile['photo'])); ?>在profile.php中发现了file_get_contents()函数,它读取了数组$profile的photo继续看代码,$profile是反序列化了$profile, $profile调用了class.php中的user对象中的show_profile()方法, 传入了username接下来看show_profile()image-20221011185518280.png调用了父类的filter方法去查看filter()image-20221011190550206.pngfilter方法是对传进去的进行过滤,把字符串中的"select , insert, update, delete, where" 替换成hacker, 并返回这个字符串回过去看show_profile()$object 调用了父类的select方法查看select()image-20221011191017190.pngselect方法查询了用户的信息,并返回了查询结果对象在show_pofile方法中,最后返回了查询结果的profile字段既然profile是从数据库中查询出来的,那一定有将profile写入出数据库的操作。查看update.php//update.php <?php require_once('class.php'); if($_SESSION['username'] == null) { die('Login First'); } if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) { $username = $_SESSION['username']; if(!preg_match('/^\d{11}$/', $_POST['phone'])) die('Invalid phone'); if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email'])) die('Invalid email'); if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10) die('Invalid nickname'); $file = $_FILES['photo']; if($file['size'] < 5 or $file['size'] > 1000000) die('Photo size error'); move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name'])); $profile['phone'] = $_POST['phone']; $profile['emaild'] = $_POST['email']; $profile['nickname'] = $_POST['nickname']; $profile['photo'] = 'upload/' . md5($file['name']); $user->update_profile($username, serialize($profile)); echo 'Update Profile Success!<a href="profile.php">Your Profile</a>'; } else { ?>在update.php中有一个序列化操作, 调用了update_profile()方法我们查看这个方法image-20221011194057660.png他这里又调用了filter()方法对username和profile进行了过滤然后调用了父类的update()方法, 查看update方法image-20221011194719967.pngupdate方法对数据库进行更新操作,重新写入了profile,在config.php中找到了关键信息, 发现flag在里面image-20221011201212936.png继续查看profile.php他读取了photo,这个photo是我们不可控的变量,我们要想办法让photo的值变成config.php $profile['phone'] = $_POST['phone']; $profile['emaild'] = $_POST['email']; $profile['nickname'] = $_POST['nickname'];这三个变量都是我们可控的发现对nickname进行了限制,不能超过10个字符image-20221011202212951.png我们可以通过数组进行绕过构造一个profile,序列化查看<?php $profile['phone'] = "18336831378"; $profile['emaild'] = "1707154109"; $profile['nickname'] = [""]; $profile['photo'] = 'upload/' . md5("111"); echo serialize($profile); ?>结果:a:4:{s:5:"phone";s:11:"18336831378";s:6:"emaild";s:10:"1707154109";s:8:"nickname";a:1:{i:0;s:0:"";}s:5:"photo";s:39:"upload/698d51a19d8a121ce581499d7b701668";}我们可以构造payload";}s:5:"photo";s:10:"config.php";}把这个payload给nickname赋值, 再序列化查看$profile['nickname'] = ['";}s:5:"photo";s:10:"config.php"'];结果a:4{s:5:"phone";s:11:"18336831378";s:6:"emaild";s:10:"1707154109";s:8:"nickname";a:1{i:0;s:34:"";}s:5:"photo";s:10:"config.php";}";}s:5:"photo";s:39:"upload/698d51a19d8a121ce581499d7b701668";}这边nickname会读取34个字符,也就是我们的payload,我们要将他逃逸出去,因为profile被传入update_profile方法会对profile进行过滤,将"select , insert, update, delete, where"这些字符串替换成hacker这样就会多出来一个字符,所以我们只要在我们的payload前面添加34个where,就会多出34个字符,我们的payload就会逃逸出来payload:在源码中有个register.php我们访问这个页面,注册一个账号,注册好后登录账号image-20221011195716878.png构造payloadwherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}打开burp对该页面进行抓包重发image-20221011210514723.png回显页面显示更新成功进入profile页面查看image-20221011210657220.png当我看到图片没有被加载出来就知道成功了查看网页源代码image-20221011210749659.png将base64复制进行解码image-20221011211531534.png拿到flag BUUCTF [FlareOn6]Overlong https://dirtycow.cn/54.html 2023-10-19T21:49:00+08:00 思路:拿到题目 使用exeinfo查看程序信息是一个无壳32位程序image-20230407103641150.png直接ida分析 v6是sub_401160函数的返回值Text[v6] = 0 在c语言中字符串是以0结尾的 这里的意思是取v6的值为字符串长度查看sub_401160函数的参数是Text &unk_402008 28image-20230407110654182.png双击&unk_402008查看值发现这是个数组image-20230409194556653.png转换一下是一个长度为176的数组image-20230409194644102.png跟进sub_401160函数查看image-20230409194415881.png继续跟进sub_401000函数这个函数对Text进行了操作image-20230409195258303.png运行程序查看发现程序消息框的内容正好是28位 也就是sub_401160函数中的第三个参数 循环的次数大胆猜想 每循环一次就处理一个&unk_402008中的字符&unk_402008中有176个字符 去掉最后一位0 就是175分字符我们只要把28次循环改成175次就可以得到flagimage-20230409200207447.png现在有两种解题思路1.将程序的代码dump下来 将循环次数改成1752.使用动调 直接将循环次数改成175我选第二种方法(太懒了)exp:使用x32dbg打开程程序发现内存地址和ida中的内存地址不一样image-20230409201225904.png接下来计算偏移地址找一个比较明显的特征就这个push Outputimage-20230409201607101.png在动调中搜索字符串image-20230409201800012.png找到output双击进去image-20230409201844690.png在动调中的内存地址为003E11EFida中的地址为004011EF将这两个地址相减就是偏移地址了image-20230409202108436.png在ida中找到push 1Ch 复制他的内存地址在动调中跳转到这个地址-20000image-20230409202254106.pngimage-20230409202454745.pngimage-20230409202508746.png右键这个地址->在内存窗口中转到->选定的地址image-20230409202557852.png右键这个1C->修改image-20230409202735076.png修改成AF(十进制的175)image-20230409202837372.png按f9运行程序image-20230409203006505.pngflag:flag{I_a_M_t_h_e_e_n_C_o_D_i_n_g@flare-on.com} BUUCTF [FlareOn3]Challenge1 https://dirtycow.cn/31.html 2023-10-19T16:00:39+08:00 思路:使用exeinfo查壳是一个无壳32位的程序image-20230409204347007.png直接上ida直接看main函数将用户的输入保存到buffer[]使用sub_401260函数处理buffer[] Str1指向处理之后sub_401260的返回值最后比较Str1和Str2的值image-20230410083548517.png跟进sub_401260函数查看瞅一眼代码 发现很眼熟 看着像base64继续往下看image-20230410090133409.png看到了byte_413000 双击进去查看发现了对base64的编码表进行了修改image-20230410090457886.png到这里题目的逻辑已经很清晰了直接写脚本跑flagexp:import base64 def main(): string1 = "ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/" string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" encode = "x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q" print(base64.b64decode(encode.translate(str.maketrans(string1,string2)))) if __name__ =="__main__": main()flag:flag{sh00ting_phish_in_a_barrel@flare-on.com} BUUCTF [HDCTF2019]Maze https://dirtycow.cn/26.html 2023-10-19T15:47:00+08:00 思路:下载题目,首先使用exeinfo查壳image-20230322162405703.png查出来是upx的壳 尝试使用脱壳工具脱壳脱完壳使用ida打开image-20230322200320034.png看到了jnz 有call了一个错误的函数 很明显是一个花指令选中那一行 在ida中点击edit->Path program->Change program bytesimage-20230327140907211.png将e8修改成90在汇编指令中e8是call 90是nop修改好之后选中红色区域 按p 创建函数 就可以发现 现在可以反汇编了image-20230327141223023.png按f5进行反汇编image-20230327141315767.png发现程序判断用户输入是否为a d s w 对asc_408078 和 dword_40807C进行操作然后通过题目名maze翻译过来就是迷宫 猜测通过用户的输入 移动一个坐标 找到flagimage-20230327151715623.png查看asc_408078的初始值是7image-20230327151810009.png查看dword_40807C 初始值是0经过一系列操作之后要使asc_408078 == 5 和 dword_40807C == -4 也是就是起始点(7,0)->终点(5,-4)image-20230327152443143.pngshift+f12查找字符串 看到了一个很可疑的字符串 看似是个迷宫把它复制出来从坐标得知 F 在第-4行 也就是说 f上面还有4行(0,-1,-2,-3)F是-4行第5个, 也就是前面还有5个 排一下版image-20230327183620752.pngflag:flag{ssaaasaassdddw}