Skip to content

Commit b3b65db

Browse files
committed
Merge branch 'master' of https://github.com/hgarrereyn/easyctf-2017-writeups into hgarrereyn-master
2 parents 5c8cdce + bcc5d45 commit b3b65db

File tree

2 files changed

+124
-4
lines changed

2 files changed

+124
-4
lines changed

programming.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ This category tests your skills at writing scripts to automate tasks that are to
77
* Fizz Buzz 1 \[50 points\]
88
* Down a Notch \[100 points\]
99
* library \[175 points\]
10-
* Fzz Buzz 2 \[200 points\]
10+
* [Fzz Buzz 2 \[200 points\]](/programming/fzz-buzz-2-200-points.md)
1111
* Things Don't Add Up \[210 points\]
1212
* Wayward Space Junk \[300 points\]
1313
* [Match Me \[300 points\]](/programming/match-me-300-points.md)
14-
15-
16-

programming/fzz-buzz-2-200-points.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Fzz Buzz 2 - 200 points
2+
3+
Oh no! Two of my keys are broken! Please help me make the same Fzz Buzz program, sans that one letter and queston marks.
4+
5+
As a side note, use of `eval()` and `exec()` is also frowned upon and will be marked invalid.
6+
7+
***This writeup is a python solution***
8+
9+
### Summary
10+
11+
The goal of this challenge was to write a fizz buzz program without using the letter `i` or the question mark character `?`. You must read an integer `n` from stdin and print that many lines of fizz buzz. For example, if `n = 17`, output:
12+
13+
```
14+
1
15+
2
16+
Fizz
17+
4
18+
Buzz
19+
Fizz
20+
7
21+
8
22+
Fizz
23+
Buzz
24+
11
25+
Fizz
26+
13
27+
14
28+
FizzBuzz
29+
16
30+
17
31+
```
32+
33+
### How to get input / print
34+
35+
In order to get user input, you must call `input()` and likewise, to print you must call `print()`. Therefore, we need some way to alias these functions without using the character `i`.
36+
37+
**Solution:**
38+
39+
Both `input` and `print` belong to the `__builtins__` module that is loaded automatically on startup. Therefore, we can find a reference to these functions by using `getattr` on the `__builtins__` module.
40+
41+
```python
42+
f = getattr(globals()['__builtins__'],'input')
43+
p = getattr(globals()['__builtins__'],'print')
44+
```
45+
46+
Then by simply escaping the `i` character we get this:
47+
48+
```python
49+
f = getattr(globals()['__bu\x69lt\x69ns__'],'\x69nput')
50+
p = getattr(globals()['__bu\x69lt\x69ns__'],'pr\x69nt')
51+
```
52+
53+
Now `f` will call `input` and `p` will call `print`.
54+
55+
### How to loop
56+
57+
Since the user provides the number of lines to print, we must find some way to loop from `1` to `n`.
58+
59+
**Solution:**
60+
61+
Let's use recursion. We will read `n` from the input and then define a function `go(k)` that prints the text for line `k` and calls itself with `k+1` if `k < n`. Finally, we will start it off by calling `go(1)` That looks like this:
62+
63+
```python
64+
n = f() # Using our alias
65+
66+
def go(k):
67+
# Do some print magic here
68+
if (k < n):
69+
go(k+1)
70+
71+
go(1) # Start the chain
72+
```
73+
74+
### How to use conditionals?
75+
76+
We ran into a problem in our last task: we can't use `if` since it has an `i`. Therefore, we must find some other way to get conditional behavior.
77+
78+
**Solution:**
79+
80+
How about short-circuiting? In python (and many other languages) a conditional will stop evaluation if one side can determine the entire expression. For example, in the following expression, the conditional inside `print` checks if `a == 1`. Since that is `False`, there is no way for the expression to be true (because `False AND x == False` regardless of `x`) Therefore, the expression `b == 1` isn't even evaluated.
81+
82+
```python
83+
a = 5
84+
b = 3
85+
86+
print(a == 1 and b == 1)
87+
```
88+
89+
We can use this to our advantage. How about if we put the check as the first conditional and the print as our second. Therefore, if the check succeeds, we print the line. Here is what that looks like:
90+
91+
```python
92+
a = ((k % 15 == 0) and p('F\x69zzBuzz'))
93+
```
94+
95+
In the previous line, we first check if `k` (the line number) is divisible by `3` and `5` (or just `15`). If it is not, the conditional short-circuits and the right side is not evaluated. If it is, we call `p('F\x69zzBuzz')` which prints `FizzBuzz`. (The `a =` is just so that it is a valid expression).
96+
97+
### Putting it all together
98+
99+
Therefore, using all of these ideas, we can come up with the following program:
100+
101+
```python
102+
# Create aliases
103+
f = getattr(globals()['__bu\x69lt\x69ns__'],'\x69nput')
104+
p = getattr(globals()['__bu\x69lt\x69ns__'],'pr\x69nt')
105+
106+
# Get user input
107+
n = f()
108+
109+
# Prints text for line k and calls itself with the next line
110+
def go(k):
111+
a = ((k % 15 == 0) and p('F\x69zzBuzz'))
112+
a = ((k % 3 != 0 and k % 5 == 0) and p('Buzz'))
113+
a = ((k % 3 == 0 and k % 5 != 0) and p('F\x69zz'))
114+
a = ((k % 3 != 0 and k % 5 != 0) and p(k))
115+
a = ((k < n) and go(k + 1))
116+
117+
go(1)
118+
```
119+
120+
121+
### External Writeups
122+
123+
* \(none\)

0 commit comments

Comments
 (0)