gift-card
author: deomkicer
In this challenge we will get this attachment, here is the full main.py
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import random
import signal
FLAG = open("../flag.txt").read()
class GiftShop:
# TODO: design better giftcard generator and validator
def __init__(self, name: str) -> None:
self.mod = lambda x: x % 256
self.Hm = self.mod(sum(name.encode()))
def generate_giftcard(self) -> str:
r = random.randbytes(15)
s = int.to_bytes(self.mod(self.Hm - self.mod(sum(r))))
signature = r + s
return signature.hex()
def validate_giftcard(self, giftcard: str) -> bool:
signature = bytes.fromhex(giftcard)
return len(signature) == 16 and self.mod(sum(signature)) == self.Hm
class Challenge:
def __init__(self, name):
self.name = name
self.balance = 100
self.items = {
"bread": {"price": 33, "callable": self.__get_bread},
"giftcard": {"price": 50, "callable": self.__get_giftcard},
"flag": {"price": 420, "callable": self.__get_flag},
}
self.redeemed_giftcard = set()
self.gift_shop = GiftShop(self.name)
def greet(self):
msg = ""
msg += f"\nWelcome, {self.name}!"
msg += f"\nOption:"
msg += f"\n [1] Check available items"
msg += f"\n [2] Buy item"
msg += f"\n [3] Redeem giftcard"
msg += f"\n [9] Input admin code"
print(msg)
def __get_bread(self):
return chr(0x1F35E)
def __get_giftcard(self):
return self.gift_shop.generate_giftcard()
def __get_flag(self):
return FLAG
def check_available(self):
msg = ""
msg += f"\nAvailable items:"
for item_name, item_info in self.items.items():
item_price = item_info["price"]
msg += f"\n [+] {item_name} (${item_price})"
return msg
def buy_item(self, item):
if item not in self.items.keys():
return f"Item {item} is not available"
if self.balance < self.items[item]["price"]:
return f"Insufficient balance"
self.balance -= self.items[item]["price"]
return self.items[item]["callable"]()
def redeem_giftcard(self, giftcard):
if giftcard in self.redeemed_giftcard:
return "Your giftcard is already used"
if not self.gift_shop.validate_giftcard(giftcard):
return "Your giftcard is invalid"
value = random.randint(30, 60)
self.balance += value
self.redeemed_giftcard.add(giftcard)
return f"You got ${value} from the giftcard"
def admin_code(self, code):
if code != FLAG:
return "Incorrect code"
self.balance += self.items["flag"]["price"]
return "Correct code"
def user_input(s):
inp = input(s).strip()
assert len(inp) < 256
return inp
def main():
name = user_input("Name: ")
challenge = Challenge(name)
challenge.greet()
while True:
print(f"\nCurrent balance: ${challenge.balance}")
match int(user_input("> ")):
case 1:
print(challenge.check_available())
case 2:
item = user_input("Item: ")
print(challenge.buy_item(item))
case 3:
giftcard = user_input("Giftcard: ")
print(challenge.redeem_giftcard(giftcard))
case 9:
code = user_input("Code: ")
print(challenge.admin_code(code))
case _:
print("Invalid option")
break
if __name__ == "__main__":
signal.alarm(60)
main()
First we can take a look in this section
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class GiftShop:
# TODO: design better giftcard generator and validator
def __init__(self, name: str) -> None:
self.mod = lambda x: x % 256
self.Hm = self.mod(sum(name.encode()))
def generate_giftcard(self) -> str:
r = random.randbytes(15)
s = int.to_bytes(self.mod(self.Hm - self.mod(sum(r))))
signature = r + s
return signature.hex()
def validate_giftcard(self, giftcard: str) -> bool:
signature = bytes.fromhex(giftcard)
return len(signature) == 16 and self.mod(sum(signature)) == self.Hm
We can see that the giftcard will be generated by 15 bytes random and 1 bytes from this expression int.to_bytes(self.mod(self.Hm - self.mod(sum(r))))
. Then to check the giftcard is valid, it will check the length (must be 16) and modulus of sum signature equal to modulus of sum name.
Ok, our goal is to buy the flag and it cost 420. The challenge is we only have 100. We can buy a giftcard, it cost 50. If we reedem the giftcard we can get random value 30 - 60. So, now the question is how do we could get as many as possible the giftcard? Since we can retry the program, my idea is to generate as many as possible the giftcard without reedeming it. After we have a lot of giftcard we can reedem it to buy the flag.
Here is the solver :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from pwn import *
context.log_level = 'error'
def buy(item):
p.sendlineafter(b"> ", b"2")
p.sendlineafter(b"Item: ", item)
return p.recvline()
code = []
for i in range(10):
p = remote(f"127.0.0.1", 21000)
p.sendlineafter(b"Name: ", b"0")
for i in range(2):
val = buy(b"giftcard")
code.append(val)
p.close()
p = remote(f"127.0.0.1", 21000)
p.sendlineafter(b"Name: ", b"0")
for i in code:
p.sendlineafter(b"> ", b"3")
p.sendlineafter(b"Giftcard: ", i.strip())
flag = buy(b"flag").strip().decode()
print("[+] The flag is: ", flag)
Output :
1
2
❯ python3 solve.py
[+] The flag is: PLACEHOLDER