1
1
from django .apps import AppConfig
2
+ from django .contrib .auth import get_user_model
3
+
4
+ import pymysql
5
+ import random
6
+
7
+ from utils .generator import random_string , random_flag
8
+ from utils .mysql import sqli_db
9
+ from utils .mysql import raw_query
10
+
11
+ from flag .models import Flag
12
+ from env .environ import ITEM_CATEGORY_SQLI
13
+ from env .credential import MYSQL_PASS
14
+
15
+
16
+ Team = get_user_model ()
17
+
2
18
3
19
4
20
class SqliConfig (AppConfig ):
5
21
name = 'sqli'
22
+
23
+
24
+ SCORE = 200
25
+
26
+ NUM_TEAM = 6
27
+ NUM_TABLE_FLAG = 1
28
+ NUM_COLUMN_FLAG = 2
29
+ NUM_ELEMENT_FLAG = 7
30
+ NUM_FLAG = NUM_TABLE_FLAG + NUM_ELEMENT_FLAG + NUM_COLUMN_FLAG
31
+
32
+ NUM_TABLE = 10
33
+ NUM_COLUMN = 5
34
+ NUM_ROW = 100
35
+
36
+ TABLE_SHOW_INTERVAL = 10
37
+
38
+ FLAG_MAX_LEN = 50
39
+
40
+
41
+ class Element :
42
+ def __init__ (self ):
43
+ self .name : str = random_string ()
44
+ self .size : int = 1
45
+ self .child : list = []
46
+
47
+ def insert_flag (self , flag : str ):
48
+ count = 0
49
+ candidates = [i for i ,value in enumerate (self .child ) if not str (value ).startswith ("PLUS{" )]
50
+ if not candidates :
51
+ return False
52
+ self .child [random .choice (candidates )].name = flag
53
+ return True
54
+
55
+
56
+ class Column (Element ):
57
+ def __init__ (self ):
58
+ super ().__init__ ()
59
+ self .elements : list = [Element () for _ in range (NUM_ROW )]
60
+ self .child = self .elements
61
+ self .size : int = NUM_ROW
62
+
63
+ def __repr__ (self ):
64
+ return self .name
65
+
66
+ def __str__ (self ):
67
+ return self .name
68
+
69
+
70
+ class Table (Element ):
71
+ def __init__ (self ):
72
+ super ().__init__ ()
73
+ self .columns : list = [Column () for _ in range (NUM_COLUMN )]
74
+ self .child = self .columns
75
+ self .size : int = NUM_COLUMN
76
+
77
+ names = []
78
+
79
+ for c in self .columns :
80
+ while True :
81
+ name = random_string ()
82
+ if name not in names :
83
+ c .name = name
84
+ names .append (name )
85
+ break
86
+
87
+ def __repr__ (self ):
88
+ return self .name
89
+
90
+ def __str__ (self ):
91
+ return self .name
92
+
93
+ def show (self ):
94
+ print (self .name )
95
+ print ("-" * (NUM_COLUMN * 13 ))
96
+ for i in self .columns :
97
+ print ("%10s |" % (i .name [:10 ]), end = ' ' )
98
+ print ()
99
+ print ("-" * (NUM_COLUMN * 13 ))
100
+ for e_idx in range (NUM_ROW ):
101
+ for col in self .columns :
102
+ print ("{:10s} |" .format (col .elements [e_idx ].name [:10 ]), end = ' ' )
103
+ print ()
104
+ print ("-" * (NUM_COLUMN * 13 ))
105
+ print ()
106
+
107
+ def to_sql (self , db_name : str ):
108
+ result = "CREATE TABLE " + db_name + ".`" + self .name + "` (" + " VARCHAR(100), " .join ("`" + c .name + "`" for c in self .columns ) + " VARCHAR(100)); \n "
109
+ cols = "`, `" .join (c .name for c in self .columns )
110
+
111
+ for e_idx in range (NUM_ROW ):
112
+ data = "', '" .join (c .elements [e_idx ].name for c in self .columns )
113
+ result += f"INSERT INTO { db_name } .`{ self .name } ` (`{ cols } `) VALUES ('{ data } '); \n "
114
+ print (result )
115
+ return result
116
+
117
+
118
+ class DB (Element ):
119
+ def __init__ (self , _name : str ):
120
+ super ().__init__ ()
121
+ self .name : str = _name
122
+ self .size : int = NUM_TABLE
123
+ self .tables : list = [Table () for _ in range (NUM_TABLE )]
124
+ self .child = self .tables
125
+
126
+ def __repr__ (self ):
127
+ return self .name
128
+
129
+ def __str__ (self ):
130
+ return self .name
131
+
132
+ def show (self ):
133
+ print (f"[+] DB: { self .name } " )
134
+ for t in self .tables :
135
+ t .show ()
136
+
137
+ def to_sql (self ):
138
+ result = ""
139
+ for table in self .tables :
140
+ result += table .to_sql (self .name )
141
+ return result
142
+
143
+
144
+
145
+ def add_flag (max_len ):
146
+ flag = random_flag (max_len )
147
+ Flag .objects .create (flag = flag , score = SCORE , category = ITEM_CATEGORY_SQLI )
148
+ return flag
149
+
150
+
151
+ def get_flag_set (max_len ):
152
+ return [add_flag (FLAG_MAX_LEN ) for _ in range (NUM_FLAG )]
153
+
154
+
155
+ def generate_db (team_name : str ):
156
+ idx = 0
157
+ db = DB (team_name )
158
+ team_flag_set = get_flag_set (60 )
159
+
160
+ for _ in range (NUM_TABLE_FLAG ):
161
+ db .insert_flag (team_flag_set [idx ])
162
+ idx += 1
163
+
164
+ for _ in range (NUM_COLUMN_FLAG ):
165
+ table = random .choice (db .tables )
166
+ table .insert_flag (team_flag_set [idx ])
167
+ idx += 1
168
+
169
+ for _ in range (NUM_ELEMENT_FLAG ):
170
+ table = random .choice (db .tables )
171
+ col = random .choice (table .columns )
172
+ col .insert_flag (team_flag_set [idx ])
173
+ idx += 1
174
+
175
+
176
+ query = f"DROP DATABASE IF EXISTS { team_name } ;\n "
177
+ query += f"CREATE DATABASE { team_name } ;\n "
178
+ query += f"CREATE USER { team_name } @'%' IDENTIFIED BY '{ MYSQL_PASS } ';\n "
179
+ query += f"GRANT SELECT ON { team_name } .* TO { team_name } @'%';\n "
180
+ query += f"FLUSH privileges;"
181
+
182
+ raw_query (sqli_db (), query )
183
+ raw_query (sqli_db (), db .to_sql ())
184
+
185
+
186
+
187
+ def query_sql (attack_team_name : str , target_team_name : str , query : str ):
188
+ if attack_team_name == target_team_name :
189
+ return False , "Attacked yourself" , 400
190
+
191
+ try :
192
+ target_team = Team .objects .get (username = target_team_name )
193
+ except model .DoesNotExist :
194
+ return False , "No Such Team" , 404
195
+
196
+ ok , message , status_code = is_valid_query (target_team , query )
197
+ if not ok :
198
+ return False , message , status_code
199
+
200
+ succeed , res = raw_query (sqli_db (target_team_name , MYSQL_PASS ), query )
201
+
202
+ sqli_log = SqliLog .objects .create ()
203
+ sqli_log .from_team = attack_team_name
204
+ sqli_log .to_team = target_team_name
205
+ sqli_log .query = query
206
+ sqli_log .succeed = succeed
207
+ sqli_log .return_value = res
208
+ sqli_log .save ()
209
+
210
+ return succeed , res , 200
211
+
212
+
213
+
214
+ def is_valid_query (target_team : Team , query : str ):
215
+ max_len = target_team .sqli_filter .max_len
216
+ if max_len < len (query ):
217
+ return False , "Too Long Query" , 400
218
+
219
+ regex_filter_list = target_team .sqli_filter .regex_rule_list .all ()
220
+ for r in regex_filter_list :
221
+ p = re .compile (r .regexp , re .I )
222
+ if p .match (query ):
223
+ return False , "Blocked by Regex" , 400
224
+
225
+ return True , "" , 200
0 commit comments