-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlil_app.broken_top_ten
209 lines (166 loc) · 4.96 KB
/
lil_app.broken_top_ten
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#!perl
# this is an app the tries to demonstrate the OWASP top ten vulnerabilities
# they are commented inline. please don't take the code here as good
# practice, it is anything but and *intentionally* full of vulnerabilities
# to demo them. i take no responsibility if you use this code in your
# production environment and then get p0wned. you can find the various
# vulnerabilities by searching for OWASP
use strict;
use warnings;
use Mojolicious::Lite -signatures;
use Try::Tiny::SmartCatch;
use XML::LibXML;
use DBI;
$ENV{MOJO_LOG_LEVEL} = 'debug';
#
# helpers
#
helper logged_in_user => sub ( $c ) {
return $c->session->{username} || 0;
};
helper get_user => sub ( $c,$username ) {
my $dbh = DBI->connect(
"dbi:SQLite:dbname=lil_app.sqlite3","","",
{
PrintError => 0,
AutoCommit => 1,
AutoInactiveDestroy => 1,
RaiseError => 1,
}
) or die( "unable to create db: $DBI::errstr\n" );
# OWASP 1. SQL Injection - we should be using bind variable here
# as users could inject SQL into the query here and cause all
# sorts of damage
return $dbh->selectrow_array( "
SELECT username, password, mobile FROM users
WHERE username = ?
",undef,$username );
};
#
# routes
#
get '/' => sub ( $c ) {
return $c->render;
};
get '/exception' => sub ( $c ) {
# OWASP 3. Sensitive Data Exposure - running this under morbo
# will reveal lots of internal details about the app, which
# could be used to attack the app or reverse engineer it
$c->render( text => "Exception!" );
};
any '/login' => sub ( $c ) {
my $username = $c->param( "username" ) || '';
my $password = $c->param( "password" ) || '';
$c->stash( username => $username );
$c->stash( error => undef );
try sub {
my ( $db_username,$db_password ) = $c->get_user( $username );
if ( $db_username ) {
if ( $db_password eq $password ) {
$c->session(
logged_in => 1,
username => $username,
);
$c->redirect_to( '/' );
} else {
# OWASP 2. Broken Authentication - we are revealing that the
# user exists, so now only the password needs to be figured out
$c->stash( 'error' => "There was a problem with your login details: \"$username\"" );
}
} elsif ( $username ) {
# OWASP 7. XSS (reflected) - the template needs to use the <%= tags rather
# than the <%== tags to ensure the interpolated variables are encoded
$c->stash( 'error' => "There was a problem with your login \"$username\"" );
}
},
catch_default sub {
chomp( my $e = $_ );
app->log->error( $e );
# OWASP 3. Sensitive Data Exposure - we are sticking an error in
# the stash here, which could reveal details of the internal
# implementation that could be used to further attack the app.
# we should probably catch certain exceptions to decide on how
# we will report them back to the user
$c->stash( error => "There was a problem with your login details: \"$username\"" );
};
return $c->render;
};
post '/soap' => sub ( $c ) {
my $xml = $c->req->body;
my $dom = XML::LibXML->load_xml(
string => $xml,
# OWASP 4. XML External Entities - XML that references external entities
# needs sanitising and/or whitelisting. here we have the expand_entities
# set to true, overriding the default, and thus opening the exploit
expand_entities => 0,
);
$c->render(
format => 'xml',
text => $dom->toString,
);
};
get '/mobile/:username' => sub ( $c ) {
my $logged_in_username = $c->logged_in_user;
$c->reply->not_found
if $logged_in_username ne $c->param( 'username' );
# OWASP 5. Broken Access Control - only super users and the user the
# settings relate to should be able to access the settings
my ( undef,undef,$mobile ) = $c->get_user( $c->param( 'username' ) );
$c->render( text => $mobile );
};
get '/logout' => sub ( $c ) {
$c->session( expires => 1 );
$c->redirect_to( '/' );
};
#
# hooks
#
hook 'after_dispatch' => sub {
my ( $c ) = @_;
# OWASP 6. Security Misconfiguration - misconfigured HTTP headers and
# poor defaults can lead to insecure transport
$c->res->headers->cache_control( 'no-store' );
$c->res->headers->header( Pragma => 'no-cache' );
$c->res->headers->header( 'X-Frame-Options' => 'SAMEORIGIN' );
};
# OWASP 6. Security Misconfiguration - default configurations
app->secrets( ['some sort of secure phrase'] );
#
# startup the app
#
app->start;
#
# templates
#
__DATA__
@@ .html.ep
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<% if ( my $username = $c->session->{username} ) { %>
Welcome <%= $username %>!
<% } else { %>
<a href="/login">Login</a>
<% } %>
</body>
</html>
@@ login.html.ep
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<form action="/login" method="POST">
Username: <input name="username" /><br />
Password: <input name="password" type="password" autocomplete="off"/><br />
<button name="submit" value="Login" title="Login" type="submit" >Login</button>
</form>
<% if ( $error ) { %>
<%= $error %>!
<% } %>
</body>
</html>