Skip to content

Commit 19e4719

Browse files
committed
feat: self-evaluation and updates for owasp module
1 parent a5caf26 commit 19e4719

File tree

10 files changed

+269
-118
lines changed

10 files changed

+269
-118
lines changed

modules/2-owasp.livemd

Lines changed: 110 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1+
<!-- livebook:{"persist_outputs":true} -->
2+
13
# ESCT: Part 2 - OWASP
24

35
```elixir
4-
Mix.install([
5-
{:grading_client, path: "#{__DIR__}/grading_client"},
6-
:bcrypt_elixir,
7-
:httpoison,
8-
{:absinthe, "~> 1.7.0"},
9-
{:phoenix, "~> 1.0"},
10-
{:plug, "~> 1.3.2"}
11-
])
6+
Mix.install(
7+
[
8+
{:grading_client, path: "#{__DIR__}/grading_client"}
9+
],
10+
config_path: "#{__DIR__}/grading_client/config/config.exs"
11+
)
1212

1313
md5_hash = :crypto.hash(:md5, "users_password")
1414
bcrypt_salted_hash = Bcrypt.hash_pwd_salt("users_password")
@@ -103,27 +103,56 @@ Notable CWEs included are CWE-259: Use of Hard-coded Password, CWE-327: Broken o
103103

104104
_Please uncomment the function call that you believe is correct._
105105

106+
<!-- livebook:{"attrs":"eyJtb2R1bGVfaWQiOm51bGwsInF1ZXN0aW9uX2lkIjpudWxsLCJzb3VyY2UiOiJkZWZtb2R1bGUgUGFzc3dvcmRDb21wYXJlIGRvXG4gIGRlZiBvcHRpb25fb25lKHBhc3N3b3JkLCBtZDVfaGFzaCkgZG9cbiAgICBjYXNlIDpjcnlwdG8uaGFzaCg6bWQ1LCBwYXNzd29yZCkgPT0gbWQ1X2hhc2ggZG9cbiAgICAgIHRydWUgLT4gOmVudHJ5X2dyYW50ZWRfb3AxXG4gICAgICBmYWxzZSAtPiA6ZW50cnlfZGVuaWVkX29wMVxuICAgIGVuZFxuICBlbmRcblxuICBkZWYgb3B0aW9uX3R3byhwYXNzd29yZCwgYmNyeXB0X3NhbHRlZF9oYXNoKSBkb1xuICAgIGNhc2UgQmNyeXB0LnZlcmlmeV9wYXNzKHBhc3N3b3JkLCBiY3J5cHRfc2FsdGVkX2hhc2gpIGRvXG4gICAgICB0cnVlIC0+IDplbnRyeV9ncmFudGVkX29wMlxuICAgICAgZmFsc2UgLT4gOmVudHJ5X2RlbmllZF9vcDJcbiAgICBlbmRcbiAgZW5kXG5lbmRcblxuIyBETyBOT1QgQ0hBTkdFIENPREUgQUJPVkUgVEhJUyBMSU5FID09PT09PT09PT09PT09PT09PT09PT09PT1cblxuIyBQYXNzd29yZENvbXBhcmUub3B0aW9uX29uZShcInVzZXJzX3Bhc3N3b3JkXCIsIG1kNV9oYXNoKVxuIyBQYXNzd29yZENvbXBhcmUub3B0aW9uX3R3byhcInVzZXJzX3Bhc3N3b3JkXCIsIGJjcnlwdF9zYWx0ZWRfaGFzaCkifQ","chunks":[[0,178],[180,859]],"kind":"Elixir.GradingClient.GradedCell","livebook_object":"smart_cell"} -->
107+
106108
```elixir
107-
defmodule PasswordCompare do
108-
def option_one(password, md5_hash) do
109-
case :crypto.hash(:md5, password) == md5_hash do
110-
true -> :entry_granted_op1
111-
false -> :entry_denied_op1
109+
module_id = Kino.Input.select("Module", [{OWASP, "OWASP"}])
110+
question_id = Kino.Input.number("Question ID")
111+
Kino.render(Kino.Layout.grid([module_id, question_id], columns: 2))
112+
nil
113+
114+
module_id = Kino.Input.read(module_id)
115+
question_id = Kino.Input.read(question_id)
116+
117+
result =
118+
defmodule PasswordCompare do
119+
def option_one(password, md5_hash) do
120+
case :crypto.hash(:md5, password) == md5_hash do
121+
true -> :entry_granted_op1
122+
false -> :entry_denied_op1
123+
end
112124
end
113-
end
114125

115-
def option_two(password, bcrypt_salted_hash) do
116-
case Bcrypt.verify_pass(password, bcrypt_salted_hash) do
117-
true -> :entry_granted_op2
118-
false -> :entry_denied_op2
126+
def option_two(password, bcrypt_salted_hash) do
127+
case Bcrypt.verify_pass(password, bcrypt_salted_hash) do
128+
true -> :entry_granted_op2
129+
false -> :entry_denied_op2
130+
end
119131
end
120132
end
133+
134+
case GradingClient.check_answer(module_id, question_id, result) do
135+
:correct ->
136+
IO.puts([IO.ANSI.green(), "Correct!", IO.ANSI.reset()])
137+
138+
{:incorrect, help_text} when is_binary(help_text) ->
139+
IO.puts([IO.ANSI.red(), "Incorrect: ", IO.ANSI.reset(), help_text])
140+
141+
_ ->
142+
IO.puts([IO.ANSI.red(), "Incorrect.", IO.ANSI.reset()])
121143
end
144+
```
122145

123-
# DO NOT CHANGE CODE ABOVE THIS LINE =========================
146+
<!-- livebook:{"output":true} -->
124147

125-
# PasswordCompare.option_one("users_password", md5_hash)
126-
# PasswordCompare.option_two("users_password", bcrypt_salted_hash)
148+
```
149+
Incorrect: Research MD5 Rainbow Tables
150+
```
151+
152+
<!-- livebook:{"output":true} -->
153+
154+
```
155+
:ok
127156
```
128157

129158
<!-- livebook:{"branch_parent_index":3} -->
@@ -244,19 +273,58 @@ Notable CWE included is CWE-1104: Use of Unmaintained Third-Party Components
244273

245274
### <span style="color:red">QUIZ</span>
246275

247-
**Which of the outdated components currently installed is vulnerable?**
276+
**Which of the outdated components listed below is vulnerable?**
248277

249278
_Please change the atom below to the name of the vulnerable package installed in this Livebook AND update the afflicted package._
250279

251-
_HINT: Installed dependencies can be found at the very top, it was the very first cell you ran._
280+
_HINT: Check the changelogs for each dependency._
281+
282+
<!-- livebook:{"attrs":"eyJtb2R1bGVfaWQiOm51bGwsInF1ZXN0aW9uX2lkIjpudWxsLCJzb3VyY2UiOiJhbnN3ZXIgPSBcbiAgS2luby5JbnB1dC5zZWxlY3QoXCJBbnN3ZXJcIiwgW1xuICAgIHs6ZWN0bywgXCJFY3RvIHYyLjIuMlwifSxcbiAgICB7Om54LCBcIk54IHYwLjUuMFwifSxcbiAgICB7OnBsdWcsIFwiUGx1ZyB2MS4zLjJcIn1cbiAgXSlcblxuS2luby5yZW5kZXIoYW5zd2VyKVxuXG5LaW5vLklucHV0LnJlYWQoYW5zd2VyKSJ9","chunks":[[0,178],[180,631]],"kind":"Elixir.GradingClient.GradedCell","livebook_object":"smart_cell"} -->
252283

253284
```elixir
254-
# CHANGE ME
255-
vulnerable_dependency = :vulnerable_dependency
285+
module_id = Kino.Input.select("Module", [{OWASP, "OWASP"}])
286+
question_id = Kino.Input.number("Question ID")
287+
Kino.render(Kino.Layout.grid([module_id, question_id], columns: 2))
288+
nil
289+
290+
module_id = Kino.Input.read(module_id)
291+
question_id = Kino.Input.read(question_id)
292+
293+
result =
294+
(
295+
answer =
296+
Kino.Input.select("Answer",
297+
ecto: "Ecto v2.2.2",
298+
nx: "Nx v0.5.0",
299+
plug: "Plug v1.3.2"
300+
)
301+
302+
Kino.render(answer)
303+
Kino.Input.read(answer)
304+
)
305+
306+
case GradingClient.check_answer(module_id, question_id, result) do
307+
:correct ->
308+
IO.puts([IO.ANSI.green(), "Correct!", IO.ANSI.reset()])
309+
310+
{:incorrect, help_text} when is_binary(help_text) ->
311+
IO.puts([IO.ANSI.red(), "Incorrect: ", IO.ANSI.reset(), help_text])
312+
313+
_ ->
314+
IO.puts([IO.ANSI.red(), "Incorrect.", IO.ANSI.reset()])
315+
end
316+
```
317+
318+
<!-- livebook:{"output":true} -->
256319

257-
# DO NOT CHANGE CODE BELOW THIS LINE ============================
258-
Application.spec(vulnerable_dependency)[:vsn] |> List.to_string() |> IO.puts()
259-
IO.puts(vulnerable_dependency)
320+
```
321+
Incorrect: Check the changelog for the next minor or major release.
322+
```
323+
324+
<!-- livebook:{"output":true} -->
325+
326+
```
327+
:ok
260328
```
261329

262330
<!-- livebook:{"branch_parent_index":3} -->
@@ -389,4 +457,18 @@ case HTTPoison.get(user_inputted_url) do
389457
end
390458
```
391459

460+
<!-- livebook:{"output":true} -->
461+
462+
```
463+
This is the IP belonging to your Livebook instance:
464+
179.241.241.114
465+
466+
```
467+
468+
<!-- livebook:{"output":true} -->
469+
470+
```
471+
:ok
472+
```
473+
392474
[**<- Previous Module: Introduction**](./1-introduction.livemd) || [**Next Module: Secure SDLC Concepts ->**](./3-ssdlc.livemd)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import Config

modules/grading_client/lib/grading_client.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ defmodule GradingClient do
88
"""
99

1010
@spec check_answer(any(), any(), any()) :: :correct | {:incorrect, String.t() | nil}
11-
def check_answer(answer, module_id, question_id) do
11+
def check_answer(module_id, question_id, answer) do
1212
GradingClient.Answers.check(module_id, question_id, answer)
1313
end
1414
end

modules/grading_client/lib/grading_client/answers.ex

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ defmodule GradingClient.Answers do
2121

2222
{answers, _} = Code.eval_file(filename)
2323

24-
Enum.each(answers, fn answer ->
25-
:ets.insert(@table, {{answer.module_id, answer.question_id}, answer})
26-
end)
24+
modules =
25+
MapSet.new(answers, fn answer ->
26+
:ets.insert(@table, {{answer.module_id, answer.question_id}, answer})
27+
answer.module_id
28+
end)
2729

28-
{:ok, nil}
30+
{:ok, %{modules: modules}}
2931
end
3032

3133
@doc """
@@ -36,6 +38,19 @@ defmodule GradingClient.Answers do
3638
GenServer.call(__MODULE__, {:check, module_id, question_id, answer})
3739
end
3840

41+
@doc """
42+
Returns the list of modules.
43+
"""
44+
@spec get_modules() :: [atom()]
45+
def get_modules() do
46+
GenServer.call(__MODULE__, :get_modules)
47+
end
48+
49+
@impl true
50+
def handle_call(:get_modules, _from, state) do
51+
{:reply, state.modules, state}
52+
end
53+
3954
@impl true
4055
def handle_call({:check, module_id, question_id, answer}, _from, state) do
4156
result =
@@ -44,6 +59,9 @@ defmodule GradingClient.Answers do
4459
{:incorrect, "Question not found"}
4560

4661
[{_id, %Answer{answer: correct_answer, help_text: help_text}}] ->
62+
dbg(answer)
63+
dbg(correct_answer)
64+
4765
if answer == correct_answer do
4866
:correct
4967
else
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
defmodule GradingClient.GradedCell do
2+
use Kino.JS
3+
use Kino.JS.Live
4+
use Kino.SmartCell, name: "Graded Cell"
5+
6+
@impl true
7+
def init(attrs, ctx) do
8+
source = attrs["source"] || ""
9+
10+
{:ok, assign(ctx, source: source, module_id: nil, question_id: nil),
11+
editor: [source: source, language: "elixir"]}
12+
end
13+
14+
@impl true
15+
def handle_connect(ctx) do
16+
{:ok, %{}, ctx}
17+
end
18+
19+
@impl true
20+
def handle_editor_change(source, ctx) do
21+
{:ok, assign(ctx, source: source)}
22+
end
23+
24+
@impl true
25+
def to_attrs(ctx) do
26+
%{
27+
"source" => ctx.assigns.source,
28+
"module_id" => ctx.assigns.module_id,
29+
"question_id" => ctx.assigns.question_id
30+
}
31+
end
32+
33+
@impl true
34+
def to_source(attrs) do
35+
dbg(attrs)
36+
37+
options = Enum.map(GradingClient.Answers.get_modules(), &{&1, inspect(&1)})
38+
39+
inputs =
40+
quote do
41+
module_id = Kino.Input.select("Module", unquote(options))
42+
question_id = Kino.Input.number("Question ID")
43+
44+
Kino.render(Kino.Layout.grid([module_id, question_id], columns: 2))
45+
nil
46+
end
47+
48+
source_ast =
49+
try do
50+
source = Code.string_to_quoted!(attrs["source"])
51+
52+
quote do
53+
module_id = Kino.Input.read(module_id)
54+
question_id = Kino.Input.read(question_id)
55+
56+
result = unquote(source)
57+
58+
case GradingClient.check_answer(module_id, question_id, result) do
59+
:correct ->
60+
IO.puts([IO.ANSI.green(), "Correct!", IO.ANSI.reset()])
61+
62+
{:incorrect, help_text} when is_binary(help_text) ->
63+
IO.puts([IO.ANSI.red(), "Incorrect: ", IO.ANSI.reset(), help_text])
64+
65+
_ ->
66+
IO.puts([IO.ANSI.red(), "Incorrect.", IO.ANSI.reset()])
67+
end
68+
end
69+
rescue
70+
error ->
71+
IO.inspect(error)
72+
{:<<>>, [delimiter: ~s["""]], [attrs["source"] <> "\n"]}
73+
end
74+
75+
[
76+
Kino.SmartCell.quoted_to_string(inputs),
77+
Kino.SmartCell.quoted_to_string(source_ast)
78+
]
79+
end
80+
81+
@impl true
82+
def handle_connect(ctx) do
83+
{:ok, %{}, ctx}
84+
end
85+
86+
asset "main.js" do
87+
"""
88+
export function init(ctx, payload) {
89+
ctx.importCSS("main.css");
90+
91+
root.innerHTML = `
92+
<div class="app header">
93+
<div class="text-lg font-bold">Graded Cell</div>
94+
</div>
95+
`;
96+
}
97+
"""
98+
end
99+
100+
asset "main.css" do
101+
"""
102+
.app {
103+
padding: 8px 16px;
104+
border: solid 1px #cad5e0;
105+
border-radius: 0.5rem 0.5rem 0 0;
106+
border-bottom: none;
107+
}
108+
109+
.header {
110+
display: grid;
111+
grid-template-columns: 3fr 1fr 1fr;
112+
gap: 8px;
113+
}
114+
"""
115+
end
116+
end

0 commit comments

Comments
 (0)