Table name exists injection
When calling db.multiple_insert
to insert data, the internally implemented SQL statement uses the form of splicing as follows
def multiple_insert(self, tablename, values, seqname=None, _test=False):
"""
Inserts multiple rows into `tablename`. The `values` must be a list of
dictionaries, one for each row to be inserted, each with the same set
of keys. Returns the list of ids of the inserted rows.
Set `seqname` to the ID if it's not the default, or to `False`
if there isn't one.
>>> db = DB(None, {})
>>> db.supports_multiple_insert = True
>>> values = [{"name": "foo", "email": "[email protected]"}, {"name": "bar", "email": "[email protected]"}]
>>> db.multiple_insert('person', values=values, _test=True)
<sql: "INSERT INTO person (email, name) VALUES ('[email protected]', 'foo'), ('[email protected]', 'bar')">
"""
if not values:
return []
if not self.supports_multiple_insert:
out = [
self.insert(tablename, seqname=seqname, _test=_test, **v)
for v in values
]
if seqname is False:
return None
else:
return out
keys = values[0].keys()
# @@ make sure all keys are valid
for v in values:
if v.keys() != keys:
raise ValueError("Not all rows have the same keys")
# enforce query order for the above doctest compatibility with Py3
keys = sorted(keys)
sql_query = SQLQuery(
"INSERT INTO %s (%s) VALUES " % (tablename, ", ".join(keys))
)
for i, row in enumerate(values):
if i != 0:
sql_query.append(", ")
SQLQuery.join(
[SQLParam(row[k]) for k in keys],
sep=", ",
target=sql_query,
prefix="(",
suffix=")",
)
When the values parameter is passed by the front-end combination, the current end passes in a json value like {"title":"admin","content":"admin"}
to the text parameterdb.multiple_insert("entries" , [text])
. The form of the insert statement is "INSERT INTO %s (%s) VALUES"% (tablename, ", ".join(keys))
, which causes injection on the table name. There are special symbol filtering and string conversion on the parameters, but the table name is not processed
Input parameters:
{"title": "222222","content)%20VALUES%20('admin'%20or%20updatexml(1,concat(0x7e,(version())),0)%20or%20'')%3b#(": "qweqwe"}
sql_query:
<class 'tuple'>: (<sql: "INSERT INTO entries (content) VALUES ('admin' or updatexml(1,concat(0x7e,(version())),0) or '');#(, title) VALUES ('qweqwe', '222222')">, <sql: 'SELECT last_insert_id();'>)
Finally, it will report an error and execute the sql statement:
pymysql.err.InternalError: (1105, "XPATH syntax error: '~5.7.26'")
So, is it possible not to use splicing or to filter the table name as well