개발자의 해킹 얘기 — N-day 취약점 리뷰(Django 4.0.5/SQL Injection)

June
None
Published in
5 min readMar 4, 2023
출처: https://www.sitepoint.com/how-to-protect-your-website-against-sql-injection-attacks/

안녕하세요. 휴먼스케이프 june입니다.

이번 시리즈에서는 해킹, 취약점에 대한 얘기를 자유형식으로 연재할 예정입니다.

그리고 이번 시간엔 Django 4.0.5버전에서 발견된 SQL Injection 취약점에 대해 얘기해보도록 하겠습니다.

사용하는 패키지관련 취약점 정보는 snyk사이트를 이용해 간편하게 확인할 수 있습니다.

POC는 github에 잘 올라와 있으며, 이번 편에서는 해당 POC를 기반으로 설명합니다.

SQL Injection

sql injection은 user의 입력값이 들어가는 곳에 sql을 넣어 비정상적인 동작을 하도록 유도하는것을 말합니다.

로그인 sql구문을 예로 들어보겠습니다.

select * from users where id=’{user_id}’ and password=’{password}’;

만약 user_id와 password에 ‘ or ‘’=’ 구문을 넣으면 모든 user를 가져오게 되며 로그인에 성공하게 됩니다.

select * from users where id=’' or ''='’ and password=’' or ''='’;

id가 test인 유저가 있을 경우 로그인에 통과하도록 할 수도 있습니다.

select * from users where id=’test’ and password=’' or ''='’;

이를 응용하면 db의 모든 정보들을 가져올 수 있습니다.

SQL Injection의 방어방법은 크게 2가지가 있습니다.

입력값 검증

  • 입력값을 검증해 SQL Injection을 일으키는 입력값을 사전에 치환/제거할 수 있습니다.
  • aws, cloudflare등에서 waf 등의 방화벽을 이용할 수 있습니다.

Prepared Statement 사용

  • SQL Injection에 대한 방어방법으로 가장 권장되는 방식입니다.
  • 쿼리파싱을 한 후 입력값을 바인딩합니다.
  • 입력값은 단순 텍스트로 인식되어 쿼리에 전혀 영향을 끼치지 못합니다.

CVE-2022–34265

이번 취약점은 django orm의 Extract, Trunc함수에서 발견되었습니다.

Extract는 인자로 들어온 날짜의 단위를 숫자로 추출하는 함수, Trunc는 소수점을 버리듯이 인자로 들어온 단위(hour, day, month 등)까지 날짜를 잘라 반환하는 함수입니다.

날짜의 단위를 인자로 받는 부분에서 취약점이 발생하게 되는데, 해당 함수를 사용했을때의 실제 sql 구문을 보면 다음과 같습니다.

Extract

SELECT django_datetime_extract("year","start_datetime","UTC") AS "start_year"

여기서year 부분을 year’ FROM start_datetime)) OR ``=``;SELECT PG_SLEEP(5) --으로 바꾸게 되면 sql injection이 발생합니다.

(poc의 구문을 그대로 가져오면 해킹으로 인식되어 글 작성이 안되기 때문에 일부 수정했습니다.)

SELECT django_datetime_extract("year from table_name)) or ``=``;SELECT PG_SLEEP(5) --,"start_datetime",'UTC') AS "start_year"

POC에선 SELECT PG_SLEEP(5) 를 넣었지만, 데이터베이스 삭제 등의 위험한 쿼리도 충분히 실행할 수 있습니다.

Trunc

trunc도 extract와 거의 동일하게 동작합니다.

SELECT django_datetime_trunc('year', "start_datetime", 'UTC') AS "start_year"

year 부분을year’, start_datetime)) OR ``=``;SELECT PG_SLEEP(5)-- 으로 바꿔줍니다.

SELECT django_datetime_trunc('year', start_datetime)) OR ``=``;SELECT PG_SLEEP(5)--', "start_datetime", 'UTC') AS "start_year"

위와 같이 sql injection이 발생합니다.

해당 취약점들은 trunc,extract함수의 단위 인자를 api 파라미터 등의 유저 입력으로 받아오는 경우 발생합니다.

따라서 해당 인자들을 유저 입력으로 받아오지 않도록 수정하거나 django 버전을 4.0.6 이상으로 업데이트함을 권고드립니다.

--

--