엄마보고싶다(2) – Command Injection 문턱넘기

By choirish | December 11, 2016

엄마보고싶다(2) – Command Injection 문턱넘기





Prologue


항해 한 달 째…

뜻밖의 승선, 뜻밖의 만남……..


이제는 엄마 얼굴도 잘 기억이 안난다… ㄷㄷ 어떡해

하…… 엄마아……보고싶어연……………..!!!!!!!





ㅠㅠ

흙 넘나 슬프지만 울고만 있을 수는 없지

엄마를 만나는 그 날까지 삽질은 계속된다!!!


Command Injection 탐험기

<엄마보고싶다> 2편, 지금 시작합니다 후후훟!!




지난 탐험 때, 기초탄탄/친절을 빙자하여…. Command Injection 문턱만 겨우 넘었다는…. 소식이 있었습니다 ㅎㅎㅎ (셀프 찔림 ㅋㅋㅋ)


그럼 지난 시간에 뭘 했나 다시 볼까요? ㅎㅎㅎ


  • Command Injection 소개하고…

  • File Permission 소개하고… 설정하는 명령어도 배우고…

  • SetUID, SetGID, Sticky bit “개념 only”…


ㅎㅎㅎㅎ 요약하니 별거 안한거 같은데 양은 많았죠잉 ㅎㅎㅎ

공부하면서 생기는 소소한 궁금증까지 해결하면서 내용을 추가하다보니 그렇게 되고 말았네요…ㅎㅎ

오늘은 조심해야지…하지만 어떻게 될지 아무도 모른다능 (섬뜪)


자 그래서 오늘은 본격! 진짜! 이야기를 시작합니다 ㅎㅎ


오늘 다룰 내용을 슬쩍 구경해보면~


SetUID 마저 정보오오오옥!!

Command Injection 뜯어보기!!


오늘도 별 게 없어보이지만….. ㅋㅋㅋ 또 모른다능 ㅎㅎㅎㅎㅎㅎ

무튼 오늘은 진짜 Command Injection에 좀 더 가까이 접근해보도록 합시다 ㅎㅎ


그럼 첫 번째 단계!!! SetUID부터 정복하러 갑니다!!




[발판 쌓기] SetUID는 어디에 쓰는 건가요?


지난 시간에는 진짜 SetUID 개념만 딱 설명했습니다.


- SetUID가 특별한 Permission mode라는 거

- 어떻게 SetUID를 설정하는지

- /usr/bin/passwd 파일에 SetUID가 걸려있다는 거


기억나시나요, 제가 저번 시간에 Command Injection은 이런 거에요 하면서 간단한 공격 예시를 보여드렸었는데…

거기에 SetUID가 등장했었습니다!!!! ㅎㅎㅎ


> SetUID : Set User ID upon execution !!


SetUID가 설정된 파일은 실행 시, 그 파일 “소유자”( User/Group/Others 중에 User!!! )의 권한으로 실행됩니다!!

즉, 아무리 일반사용자(Others)라도, 그 파일을 실행하는 그 순간에는 “소유자”의 이름으로 작업을 할 수 있는 것입니다!


그래서 /usr/bin/passwd 같은 파일은 root가 소유한 파일이지만 SetUID가 걸려있기 때문에,

일반 사용자라도 root의 권한으로 이 파일을 실행하여 패스워드를 변경할 수 있게 되는 거라고! 지난 시간에도 짧게 설명드렸씁니다 ㅎㅎ


그럼! 간!단!한 실행파일을 만들어서 간!단!한 테스트를 해볼까요 ㅎㅎ


(테스트 환경은 Ubuntu 14.04.3 입니다.)




◎ id를 출력하는 프로그램


SetUID가 설정된 `on_suid`와 SetUID가 설정되지 않은 `off_suid` 파일이 있습니다!



`on_suid`파일에는 뙇 SetUID가 걸려있어서 파일이름에 빨간색배경이 뙇 씌어져있는게 보입니다 ㅎ


둘 다 root권한으로 만들어졌고, system 함수로 id 명령어를 실행시키는 단순한 프로그램입니다.



먼저 off_suid를 실행해봅시다!



uid, gid, groups 모두 nyoung으로 되어있습니다!! 평소와 별다른 게 없네요~

이번엔 SetUID가 설정된! on_suid를 실행해봅니다



오홍!! root의 이름으로 된 `euid`가 새롭게 생겼어요!! ㅎㅎㅎㅎㅎㅎ `euid`는 지난 시간에도 괄호 안에 간단하게 설명했지만 Effective User ID의 줄임말로, SetUID 모드의 프로세스가 실행 중일 때! 부여되는 추가적인 권한입니다 ㅎㅎㅎㅎ 우리가 on_suid 프로그램 내에서 id를 출력할 때는 프로세스가 실행 중이므로 `euid=0`이 뙇!! 뜨는 것이죠 ㅎㅎ




◎ bash를 여는 프로그램 1


id만 출력하고 프로그램이 끝나버리니까 너무 싱거웠죠? 그래서 준비했습니다 ㅎㅎ

id를 출력하고 나서 /bin/bash 명령어를 실행하여 bash(Bourne-again shell)를 여는 프로그램을 만들어보았습니다.

SetUID를 설정해주면 root 권한의 쉘을 떨어뜨려주겠지! 기대하게 됩니다 둑흔둑흔!


앞서 예제와 같이 SetUID가 설정된 `sh1_on_suid`와 설정되지 않은 `sh1_off_suid` 파일이 있습니다!



let’s open new shell 이라며 bash를 실행하는 프로그램입니다. ( 빨간 글씨 왜 저리 흐릿하고 무서운 것…? ㅠㅠ 죄송 ㅠㅠ)



먼저 sh1_off_suid를 실행해볼까요??



역시 별다른 일이 일어나지 않았습니다!

그럼 바로 sh1_on_suid를 실행해보아요! (눈 초롱초롱 ◇ㅅ◇!!!! )



엇;; 억;;; sh1_on_suid 프로그램이 실행하는 id 명령어의 결과에는 euid가 잘 떴는데!!!

sh1_on_suid 프로그램이 연 bash에는 root 권한이 생겨나지 않았어요 ㅠㅠㅠㅠㅠㅠㅠㅠ 무슨 일이지 흙흙 넘나 슬픈 것….


그래서…….




◎ 번외1 - sh을 여는 프로그램1


혹시나 해서 `system(“/bin/bash”)` 대신에 `system(“/bin/sh”)`을 실행하는 test 파일을 만들어보았습니다.



그랬더니? bash와는 다르게 euid가 root인 쉘이 뙇! 떨어져요 wowowow



아니 bash는 안되는데 sh은 왜 되는거임???????????

그 이유를 알고 싶어서 돌아다니다보니 요러한 글을 발견했어요 오호홍!!!




※ Drop Privilege??????


Drop privilege란 sh, bash, system( ) 등을 실행할 때 euid가 아닌 ruid(Real User ID)의 권한으로 프로세스를 실행시키는 것을 말합니다.

특히 SetUID가 설정된 파일에서 일시적으로 상승된 euid의 권한으로

sh, bash, system( ) 등의 중요한 시스템 명령을 함부로 내릴 수 없게 막기 위함이죠!!


그.런.데!!!!! 위 글에 의하면…


특이하게도 Debian 계열의 리눅스가 bash에는 Drop privilege를 적용하면서,

dash같은 POSIX 쉘에는 Drop privilege를 적용하지 않는다는 것입니다.

그래서 Ubuntu에서는 실행 시 부여받은 euid의 권한으로 /bin/sh을 실행할 수 있었던 거에용! WOW! 오호홍!


여기서 잠깐 확인하고 넘어갈게요 ㅎㅎ Debian계열의 리눅스가 dash에는 Drop privilege를 적용하지 않는다고 했는데…

우리가 /bin/sh을 사용한 것과 무슨 관련있음? 이라고 생각하실 수 있어요 ㅎㅎ

sh이랑 dash가 같니? 하실 수 있어요 ㅎㅎ 그래서 알려드릴게요 ㅎㅎ

Ubuntu 6.10 부터 Ubuntu의 기본(default) 시스템 쉘이 dash로 지정되었어요! (이전엔 bash였대요!)

그래서 현재 우리가 사용하는 Ubuntu의 /bin/sh은 /bin/dash와 같은 역할을 하는 것입니다 ㅎㅎ 여기 참고! ㅎㅎ


> /bin/sh이 dash로 뙇 소프트링크 걸려있는 거 확인! 히힣





◎ 번외2 - sh을 여는 프로그램2


하…… 이렇게 궁금증을 하나 해결하나 했더니…… 궁금증 parent가 궁금증 child를 낳고 말았어요….

< 번외1 > 을 해결한 제게 이런 제보가 들어옵니다.


> 제보자1 : 근데 Ubuntu 16.04 에서는 /bin/sh도 안 먹히던데????

> 제보자2 : 근데 Ubuntu 14.04 버전도… 이제 /bin/sh 안되지 않나??? Ubuntu 업데이트를 안 하신 거 아님??


아하…..??!! 하핳….;;

. . .

먼저 제보자1의 내용을 확인해봅니다….


곧바로 64bit Ubuntu 16.04에서 똑!같!은! test파일을 만들어서 실행시켜봤는데! 오홍 제보자의 말이 맞아요!

Ubuntu 16.04 에서는 SetUID가 걸린 파일에서 /bin/sh을 쓰든,

/bin/bash를 쓰든 euid의 권한으로 쉘을 실행시킬 수가 없네요!!! 오 잘 막아놨으~


그래서 Ubuntu가 업그레이드되면서 /bin/sh도 /bin/bash 처럼 막아버렸나보네! 하고 생각했습니다….


.

.

.


그러다…. 제 눈으로 확인해보고 싶어진거죠!!

dash에도 drop privilege를 적용하도록 패치했다! 업그레이드했다! 바꿨다! 요런 내용이요!! ㅎㅎㅎㅎㅎ


쓸모 있는 정보, 쓸데없는 정보… 요리조리 헤매다가 드뎌 뙇뙇 발견했어요!!!!


# 출처 : bug.launchpad.net/ubuntu


“dash는 euid가 uid랑 다를 때, 권한을 낮추지 않고 euid로 실행돼!

그래서 root 소유의 setuid 설정된 프로그램에서 system( )으로 dash 실행시키면 위험해!!”라며

Ubuntu에 버그 리포트를 했네요!!!!!


오홍이! 그럼 리포트된 버그가 잘 해결되었을까요?



헿 “This bug was fized in the package dash - 0.5.7-4ubuntu2”라며 잘 고쳤다고 합니다…….

. . .

어? 아하????!!

Ubuntu 자체에서 이걸 고친 게 아니라!!


이건 dash의 특징이기 때문에!! dash에서 Ubuntu에 제공하는 패키지를 업그레이드 시킨 거네요~ 아항항ㅎㅎ

즉 0.5.7-4ubuntu2 package 부터는 수정이 되었다고 하네요 ㅎㅎ


그럼 이쯤에서 /bin/sh로 루트 권한의 쉘이 따졌던 제 dash 버전을 확인해봅시당.


> Ubuntu 버전 확인 :`cat /etc/issue`

> dash 버전 확인 : `apt-cache policy dash`


와…. 0.5.7-4ubuntu2부터 고쳤다고 했는데 내 꺼는 0.5.7-4unbuntu1이야… 소오름… 바로 직전 패키지인가봐용 ㄷㄷ




아 그럼 제보자2님의 의견대로 내 32bit Ubuntu 14.04도 업데이트하면 dash도 같이 업그레이드되지 않을까??

그럼 내 꺼에도 /bin/sh 안먹히지 않을까?? 솔깃합니다 훟


업데이트 기기!



그렇게 시간들여 공들여… 업데이트를 했는데… 14.04.3에서 14.04.5로 업데이트했는데!!!!!

dash 버전은 바뀌지가 않았어요………….하아.. 뭐임? ㅠㅠ



망했어엽 ㅠㅠ (캡처는 미처 못했어요… 여긴 넘어가죠 ㅎㅎ)




그래서 작전을 바꿉니다ㅋ dash 패키지를 제가 친절히 손수 업그레이드 시켜보기로 합니다…



요기에 가면 dash 패키지가 쭉 있고~

제가 선택한 건 dash 0.5.8-2.1ubuntu2 in i386 입니다. ㅎㅎ 위 캡처에서 노랑 부분 누르고 Software Center로 열기 선택하세요!!


그럼 뙇 Ubuntu Software Center가 열리고 퇗퇗 install누르면 누구나 손쉽게 dash 패키지를 설치할 수 있어요 ㅎㅎ


제가 좀 쓸데없이 헤맸어서… 요로코롬 세세하게 알려드리네요 ㅋㅋ 저는 이미 install해서 installed 뙇 뜹니다 ㅎㅎ




흐어흐어 떨리는 마음으로 dash 버전을 확인해봅니다!!



꺄꺄 Ubuntu도 업데이트된 게 보이궁~ dash도 0.5.8-2.1ubuntu2로 뙇뙇 업그레이드 되었습니다 아 성공!! ㅎㅎ

그럼 더 떨리는 마음으로

dash 업그레이드 전 실행했던 똑!같!은! test 파일( SetUID가 걸려있고 system("/bin/sh")을 실행시키는 파일! )을 실행시켜봅니다



… root 권한으로 실행이 안돼요!! ㅎㅎㅎ

업그레이드한 dash에는 이러한 SetUID 설정된 파일 실행에서 drop privilege가 적용되기 때문이졍 >. < 뿌듯하다 ㅎㅎ

정보모으느라 개..고생했지만 정리하니 뿌듯 ㅎㅎ

(이렇게 또 주저리 삼천포로 빠졌네요 죄송해요 하지만 여러분도 꼼꼼히 알아두면 좋잖아여~에이~ ㅎㅎ)


. . .


자…. 이렇게…… /bin/sh로 root 권한의 쉘을 따보았지만 그것도 잠시…

dash를 업그레이드하고, Ubuntu를 업그레이드(16.04 버전으로)하면 여전히 root 권한의 쉘을 얻을 수가 없네요….


그럼 정녕 불가능한 건가요…………..ㅠㅠ?????!


라~고 하신다면!!

제가 또 방법을 구해왔지요 하하하하하하하핳




◎ bash 쉘을 여는 프로그램2 - setreuid 설정


그건 바로바로 setreuid 함수를 이용해 권한을 설정해주는 것입니다!!!

비교를 위해 똑같이 SetUID가 걸린 sh2_on_suid와 안 걸린 sh2_off_suid를 만들어줍니다.



소스 코드를 보면서 setreuid에 대해 자세히 설명 드릴게요!



system("/bin/bash")를 하기 전에 함수 세 번째 줄에 setreuid( geteuid(), geteuid() )를 넣어줬습니다!!

setreuid 함수가 하는 일은 Set Real and Effective user ID !!

즉 Real user ID와 Effective user ID를 설정하는 역할을 합니다. ( 여기를 참고!! )


#include

int setreuid( uid_t *ruid*, uid_t *euid* );


여기서 ruid는 real user ID를, euid는 effective user ID를 말하는 거겠죠? ㅎㅎ

ruid는 일반적으로 우리가 id 명령어를 쳤을 때 나오는 uid입니다. 말 그대로 진짜 사용자 ID 라는 거에요 ㅎㅎ

SetUID모드에서 얻은 euid는 그 프로세스가 실행 중일 때 일시적으로 갖는 권한이니까 ruid와는 구별되는 개념인 거졍!!


그 전 단계에서는 SetUID 모드 상태에서 bash 쉘을 열려고 했더니, euid의 권한을 안주고 ruid의 권한으로 쉘을 줘버렸어영….


.

.

.


그래서!!!!!!! 우리는 코드에다가 setreuid( geteuid(), geteuid() ) 요런 녀석을 넣고, ruid와 euid를 모두 현재 euid로 세팅하는 겁니다 ㅎㅎㅎ


정리하면, SetUID 모드 상태에서 euid는 root니까!

( geteuid()는 딱 봐도 현재 euid를 가져와라! 하는 함수죠 ㅎㅎ )

setreuid( geteuid(), geteuid() )를 하면, ruid와 euid를 root로!! 설정해주게 됩니다 꺄꺄

(setreuid(0, 0) 이라고 해줘도 똑같은 말입니다! id number에서 0은 root를 뜻하니까요 ㅎㅎ)


그럼??! 우리가 코드 한 줄을 더해줌으로써 bash가 euid 안 쓰고 ruid 쓰려고 해도!

우리가 ruid도 root로 바꿔놨으니까, root의 쉘을 떨어뜨려줄 수 밖에 없을 것이다!  라고 예상할 수 있습니다 ㅎㅎ




진짜 그런지 확인해봅시다!!

sh2_off_suid는 당연히 SetUID 설정 안돼있으니 구냥구냥 그렇구요



대망의 sh2_on_suid를 실행하면??!!



뙇! root의 이름으로 쉘이 뜨구요~ id를 치면요~

uid=0(root)!!! ㅎㅎㅎㅎ 무려 uid가 root인 쉘을 따냅니다 ㅎㅎㅎㅎ


.

.

.


sh 사용해서 쉘 떴다고 좋다며 그대로 안 끝내고, drop privilege 공부도 하고, dash 업그레이드도 해보고,

한 발 더 나아가 setreuid도 배우고! bash도 따내니까! 좋죵?? 호호홓


네~ 이렇게 또 길어진(핵…길어짐ㅋㅋㅋㅋㅋㅋㅋㅋ) SetUID 실습을 마치고…. 흐흐

SetUID 잘 정복하셨나요? ㅎㅎ


SetUID 끝내기 전에 다시 생각해본다면!!


우리가 실습해본 것처럼… 만약 실제로 SetUID가 설정된 root 권한 파일에 취약점이 있다면?!!!!

그 취약점을 이용하여 root 권한의 쉘을 따게 되고..!! 나쁜 마음을 먹으면 얼마든지 그걸 이용해서 정보를 빼내고, 시스템을 망가뜨릴 수가 있겠졍…. ㅠㅠ

그래서!! 우리의 시스템에 SetUID가 설정된 파일이 있다면! 이러한 취약점이 생기지 않도록 잘 관리해야 하고! 또!! 호기심에 SetUID 취약점을 찾기 시작했다가… 다른 사람의 시스템에서 그걸 함부로 악용해서는 안된다는 사실! 꼭 명심하시길 바라요 ㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎ ( 다른 취약점이라도 당근 마찬가지 ㅎㅎ )


ㅎㅎㅎㅎㅎ SetUID의 발판을 잘 쌓았다면???! 이제 Command Injection을 구경하러 가볼까요 ㅎㅎ




[입문] Command Injection 뜯어보기


지난 시간에 Command Injection을 살짝 맛보기 하자며 보여드린 게 있었습니다!!

그때는 설명 거의 안하고 훅훅 진짜 훔쳐보기만 했는데!

오늘은 그 과정을 하나하나 뜯어봅시다 ㅎㅎ


.

.

.


지난 시간에 실습을 위해 “command_injection” 이라는 파일을 만들었어요!!!



File Permission이 rwsr-xr-x이고, 소유자와 소유그룹이 모두 root인 파일입니다!!

SetUID가 뙇!! s!!로 걸려있어서 파일이름에도 빨간색 배경이 뙇뙇! 표시되어있습니다.


우리 이제 권한이랑, SetUID랑 다 배웠으니까…..

왜 root 소유에 SetUID가 걸린 파일로 만들어놨냐???! 하는 게 이제 감이 딱딱오시나요? ㅎㅎ


저렇게 만들어 놓구선 일반사용자가 실행했을 때, root 권한으로 바뀌어서 이것저것 컨트롤할 수 있는지! 보려는 거졍 ㅎㅎ

그래서!!!!!! 제가 또 새로운 파일을 하나 만들어 놓은 거에요!! root 소유의 “root_file”!!!



비루한 일반 사용자 nyoung은 저 파일을 읽을 수가 없어요 ㅠㅠ 왜냐면 root_file의 File Permission은 rw-------이니까요…


.

.

.


그러면 우리 command_injection 파일의 취약점을 이용해서!! root권한을 따서!! “root_file” 읽기에 도전해보아요 >. < 설렌당!!


※주의 : 이건 위에서 dash를 업그레이드하기 전!!에 테스트한 내용입니다 ㅎㅎ;

그래서 setreuid 안해줘도 /bin/sh로 root 권한의 쉘을 딸 수 있어요! 이 점 체크하고 봐주세요 히히




command_injection 파일을 공략하기 위해서 소스코드(command_injection.c)를 다시 한번 봅시다!


사용자로부터 받은 입력값을 /bin/ls 명령어의 인자로 전달하는 아주 간단한 프로그램이네요!!!

우리는 이 프로그램을 이용해서 Command Injection을 하려고 합니다.

그러니까 파일 이름도 딱딱이 command_injection!!!


.

.

.


자… 여기서 포인트는 이겁니다!!


- 사용자로부터 “검증되지 않은 입력”을 받네??

- 그걸 /bin/ls 명령어에 갖다 붙여서 “system( ) 함수에 전달”하네??!!!


그 포인트에 대해 자세히 알아보면…


1. 검증 되지 않은 입력(Untrusted Input)이란??

프로그램이 사용자의 입력에 혹시 이상한 값이 들어가지는 않았는지 검사하지 않고 통과시킨 입력!!

예를 들면 우리가 지금 Command Injection을 하기 위해 넣을 ; 같은 값을 검사하여 필터링해야 하는데, 그러지 않은 것입니다!


2. 중요하고 위험한 system( ) 함수

system( ) 함수는 그 인자값을 시스템에 명령어로 바로 전달하는 녀석입니다!

즉 우리가 입력한 값이 명령어로 들어가는 거니까 직접적으로 시스템에 영향을 주기가 엄청 쉬운!! 중요하고 위험한 함수인 것이죠!!


그러면!! 우리는 어떠한 값을 어떤 형태로 입력해야!! 우리가 원하는 명령을 실행시킬 수 있을까요? ㅎㅎ


저희가 원하는 건 root의 권한을 좀 더 오래 지속하는 거잖아요~

원래는 이 프로그램에서 root 권한으로 /bin/ls 만 실행할 수 있는데, 우리는 root 권한을 유지하면서 다른 일도 하고 싶은 겁니다!!


여기서 !! 가장 간편하고 직접적으로 제가 원하는 명령을 실행시킬 수 있는 방법이 있습니다.

바로바로 “ `;` (세미콜론)“을 사용하는 겁니다!! 리눅스 명령어에서 ;을 사용하면 여러 개의 명령어를 한 줄에 입력할 수 있습니다!! 저는 요 밑의 링크를 참고했어요!


> How to Run Two or More Terminal Commands at Once in Linux


요로코롬 여러 개의 명령어 사이사이에 ;를 끼워주면 각각의 명령어가 모두 차례차례 실행됩니다!!


command1 ; command2 ; command3 ; ……


그러면??????! 아이디어 뿅 떠오르셨나요 ㅎㅎㅎㅎㅎㅎㅎ


.

.

.


제가 만든 command_injection 파일은 /bin/ls 를 실행시키는 명령어라고 했잖아요! ㅎㅎ

그럼 /bin/ls 말고 하나 더 실행시켜줘!! 하면서 ;를 사용해보는 겁니다 ㅎㅎㅎ


우리는 nyoung 권한으로 읽을 수 없는 root소유의 root_file 을 읽고 싶으니까!!

command_injection 파일에 "; cat root_file" 이라는 입력값을 줘 봅시다 ㅎㅎㅎ


( 즉, command_injection 프로그램 내에서는 /bin/ls ; cat root_file이라는 명령을 system( ) 함수로 실행시키는 겁니다. )


> ./command_injection “; cat root_file”


첫 번째 줄에는 /bin/ls 의 출력값이!!!

두 번째 줄에는 cat root_file 의 출력값이 뙇!!!!!


두 명령어가 차례로 잘 실행되고….. root_file의 내용이 나왔습니다!!!! 어예!!

즉!! 우리가 nyoung으로 파일을 실행하여 root의 권한으로 root_file을 읽어냈다는 뜻입니다 오홍홍 짱짱입니다 ㅎㅎ


Command Injection이 잘 먹힌 거!!!! 아시겠죠? ㅎㅎㅎㅎㅎㅎ 아이좋아 쿄쿄




그럼 하나 더 나아갑시다 ㅎㅎㅎㅎㅎㅎ


우리가 ;을 이용해서 원하는 명령어를 더 삽입할 수 있다는 건데….

좀 더 지속적으로 root 권한을! 얻고 싶다면??!

일반적으로도 시스템을 공격한다고 하면 root 권한의 쉘을 따는 것 이 이상적인 목표가 되겠죠??!

그럼 우리도 쉘을 따봅시다 ㅎㅎㅎ 간단해용 ㅎㅎㅎㅎ root 권한으로 /bin/sh 명령어를 치면 되니까요 ㅎㅎ


.

.

.


이번에는 "; cat root_file" 대신에 "; /bin/sh" 을 입력값으로 넣어줍시다


> ./command_injection “; /bin/sh”


오홍이! 영롱한#이 뜨면서 쉘을 획득합니다!! ㅎㅎㅎㅎㅎ

그럼 이제 우리는 root권한의 쉘을 아예 딴 거에요! 마음대로 명령어 치고 놀 수 있다는 거!



id 명령어로 우리가 root의 euid를 겟!한 걸 알 수 있고

cat root_file을 직접 쳐서 파일을 자유롭게 읽을 수도 있습니다 후후훟


신납니다 ㅎㅎ 역시 쉘을 따는 게 가장 짜릿하고 설레는 일이죵 ㅎㅎㅎㅎㅎ


아 그런데…….. 잠시 들러갈 곳이 있어요 ㅎㅎㅎㅎ




[짚고 가기] 왜 ; /bin/sh 하면 안되고, “; /bin/sh” 해줘야하나요??!


제가 처음에 Command Injection을 실습해보려고 하는데….

아니 나는 시키는 대로 ; 쓰고 /bin/sh 해주라고 했는데 root 권한의 쉘이 안 뜨고, nyoung의 쉘이 자꾸 뜨는 겁니다…


분명 root 소유의 파일이고, SetUID 설정도 잘 해줬는데..!! 흡


.

.

.


문제가 뭘까 헤매던 저는 깨달았죠…. ; /bin/sh 아니고 "; /bin/sh" 이라는 걸….. ㅎㅎ


1) ./command_injection ; /bin/sh (X)

2) ./command_injection “; /bin/sh” (O)


.

.

.


;의 역할이 뭐라고 했었나요?? 두 개 이상의 명령어를 쓸 수 있도록 명령어와 명령어 사이를 구분해주는 아이에요.

그런데…….. 1번처럼 쓰면?? 이렇게 되는 것입니다! ㅠㅠ


1. command_injection을 실행해줘

2. 그리고 나서 /bin/sh을 실행해줘


그래서 command_injection 파일 내의 /bin/ls에는 아무런 인자값도 전해주지 않은 게 되고,

파일 실행이 모두 끝난 뒤 nyoung의 이름으로 /bin/sh을 실행하는 거니까? #도 구경 못하고 일반 쉘 $이 뜨게 된 거죠…. 또륵


.

.

.


그럼 2번에서 쌍따옴표(“)의 역할은 무엇인가요??

바로 “이건 하나의 인자값이야~“라고 ;/bin/sh을 묶어주는 역할을 합니다!!

그래서 ; /bin/sh이 통째로 command_injection 파일의 인자값으로 들어가게 되고,

결론적으로 system( /bin/ls ; /bin/sh ) 이라는 코드가 실행되는 것이죠 ㅎㅎ 굳굳!


Command Injecton과 ;를 처음 접하신 분이라면 약간 아리까리하고 뙇! 한번에 이해가 안될 수도 있는데!!

;의 역할을 잘 이해하고 나서 1번 2번을 큰 그림으로 바라보면??!

딱 포인트가 눈에 들어올 거에요 ㅎㅎ


그래도 안되면… 계속 읽어보고…. 주변 똑똑이 지인에게 이해시켜달라고 도움요청을!! ㅎㅎ


지난 시간에 반짝!하고 구경만 했던 예제도 하나하나 해석해드렸구….

제가 헤맸던 이야기도 해드렸구 ㅎㅎㅎㅎㅎㅎㅎ (멍청이 인증;;)


하나 더 나아가 볼까요?? 호호홓




[더하기] Command Injection에는 ; 만 쓰이는 게 아니야~


앞서 함께한 Command Injection 예제에서는 명령어를 삽입할 수 있는 가장 간단한 방법으로 ;을 소개해드렸습니다! ㅎㅎ

하지만 당연히 ;말고도 활용할 수 있는 게 많죠잉~

system( ) 같은 함수가 쓰이지 않는 환경이라면 또 다른 방법을 써야 될테구요~


사용자의 입력값에 어떤 식으로든 추가적인 명령어를 넣어서 전달할 수 있다면 대부분 Command Injection이라고 할 수 있을 것이에용


Code Injection의 Wiki 페이지를 참고하면 ; 이외의 Command Injection에 대한 아이디어를 더 얻을 수 있습니다.


# 출처 : 위키피디아-코드인젝션


주로 리눅스 쉘 명령어 문법의 특징을 이용해서 명령어 간의 연결고리를 만들어주는 기호를 사용하는 겁니다! 후후훟


공격 대상 프로그램을 분석해서 취약점을 찾고!

사용자 입력값(USER_INPUT)에! 해당 취약점을 공략할 수 있는 쉘 문법의 특정 기호와!

/bin/sh 같은 치명적인 명령어(malicious_command)를! 넣어주면????!!


위 표의 오른쪽 칸(예시)에 적힌 일이 일어나면서!! 공격자가 의도한 흐름으로 프로그램을 끌어갈 수 있게 됩니다 오홍홍


.

.

.


그럼!! 방금 전 뜯어본 command_injection 파일에 ;이 아닌 다른 기호도 몇 개 써먹어 볼까요??


제가 아까 ;설명하면서!!!! terminal 에서 여러 개의 명령어를 실행시키는 방법을 참고하라면서!!!!

주소를 하나 알려드렸쨔나요! ㅎㅎㅎㅎㅎㅎ 혹시 들어가보신 분 계신가요? ㅎㅎㅎ 바로 요기!!


여기에!!! ; 말고 &&||도 매우 설명이 잘 되어있었답니다 ㅎㅎㅎ 정리해보면~


command1 ; command2; command3 …

: 터미널에서 다수의 명령어를 각각 실행시킨다.


명령어 중 하나에서 에러가 발생하더라도 다른 명령어는 개별적으로 다 실행된다.


command1 && command2 && command3 …

: 다수의 명령어를 실행시킬 때, 앞선 명령어가 에러없이 성공적으로 실행돼야만 다음 명령어로 넘어갈 수 있다.
command1이 성공해야 command2가 실행되고, 이 때 command2가 실패하면 command3는 실행되지 않는다.


command1 || command2 || command3 …

: 다수의 명령어 중 하나라도 성공하면 그 다음 명령어는 실행되지 않는다.
즉 command1부터 차례대로 실행하는데 command1이 성공하면 그 이후 명령어는 실행하지 않고,
command1이 실패하면 성공하는 명령어가 나올 때까지 다수의 명령어를 실행한다.


오홍이!! 신기한 것 ㅎㅎㅎㅎ 그럼 command_injection 파일에 &&과 ||이 잘 먹히나 테스트해봅시다 ㅎㅎ




◎ && : AND list 활용하기


command1 && command2 && command3 …


&&는 앞선 command가 성공해야만 다음 command를 실행할 수 있다고 했습니다.

그럼 command_injection 내부에서 실행되는 /bin/ls 명령어가 성공해야만!!

우리가 &&으로 이어주는 다음 명령어가 무사히 실행되겠죠??


/bin/ls는 인자값이 없어도 잘 실행되니까~ 그냥 원래 하던대로 "&& /bin/sh"이라고 전달하면

결과적으로 /bin/ls && /bin/sh의 명령을 쉘에 내려줄 것 같습니다 ㅎㅎㅎㅎ


실행하면??



오예! /bin/ls가 무사히 실행되고나서 root(#)가 잘 뜹니다!!!!




◎ || : OR list 활용하기


command1 || command2 || command3 …


||는 앞선 command가 실패해야 다음 command가 실행될 수 있다고 했습니다. (신기행 ㅎㅎ)

그럼 /bin/ls 에서 에러가 발생해야만!! 우리가 ||으로 이어주는 다음명령어가 실행되겠지용 ㅎㅎ


제가 떠올린 핵단순 에러는 ls 명령어에 [존재하지 않는 파일명]을 인자값으로 넘겨주는 거에요 ㅎㅎ

그러면 그런 파일은 존재하지 않아! 하면서 error를 띄울 거라 예상해봅니다 ㅎㅎ

(다른 에러는 또 어떤 게 있을 지 저도 궁금해요 ㅎㅎㅎㅎ 단순한 저는 이것만 우선 생각났다는 ㅎㅎ)


.

.

.


그럼 저는 "nothing || /bin/sh" 이라고 전달해볼게요 ㅎㅎ nothing은 현재 테스트 폴더에 존재하지 않는 파일입니다 ㅎㅎ

결과적으로 /bin/ls nothing || /bin/sh의 명령을 쉘에 내려줄 것 같습니다 ㅎㅎ

실행하면??



오호라! 없는 파일이라서 에러가 뜨고, root(#)가 뜹니다!

;말고 다른 것들을 활용해서 직접 root 권한이 뜨는 걸 눈으로 확인하니까 넘나 기분이 좋네요 ㅎㅎㅎㅎ

이야기를 마무리하기 전에 마지막으로!! 가볍게(핵짧을거임) 문제 하나 구경하고 마치도록 해요 ㅎㅎㅎ




[맛보기 문제] 그럼 이제 함께 풀어보아요 FTZ 3번 문제!!


해킹 공부를 해봤다 하시는 분들은 한번씩 다 풀어보셨을 HackerSchool의 FTZ 문제죠잉~

Command Injection 탐험을 하다보니 문득 비슷한 문제를 봤던 것 같아서 뒤적뒤적해가꼬 3번 문제를 발굴해냈습니다! ㅎㅎ


우리 함께 오늘 공부했다면, 문제를 탁! 보면 탁!탁! 아하! 하고 풀 수 있어야 하는 문제입니다 ㅎㅎㅎ


FTZ에 접속하는 등등의 설명은 생략할게요 ㅎㅎㅎ 문제만 잠시 인용하는 거니까~

(설명이 필요하신 분은 구글에다가 hackerschool ftz 라고 검색해주쎄영)


FTZ level3의 문제를 읽어봅시다!



autodig 프로그램이라 그러구, 뭐시기를 하는 프로그램인 거같은데……

우린 이거 다 필요없습니다…. ㅎㅎㅎ


노랑이로 표시해둔 부분!! strcat( cmd, argv[1] )이 보이십니까…. 사용자의 입력값을 받아서!

system( cmd ) 요로코롬 시스템함수에다가 전달하네요 ㅎㅎㅎㅎ

무튼 내가 입력한 값이 명령어 사이에 들어간다는 거니까!!!


저는 당당히 Command Injection을 쓰렵니다! ㅎㅎㅎ

( more hints에 오늘 우리가 배운 포인트도 모두 들어있네요! ㅎㅎㅎ )


.

.

.


공격!!!!



autodig 실행파일에 " ; /bin/bash ; "라는 입력값을 전달하면! 뙇 level4로 권한이 상승하여 쉘을 땄습니다 후후훟

(흠… 이 ftz 문제 환경도… 엄청 낮은 버전이라서… 아마 요로코롬 /bin/bash 만으로 root의 쉘이 따진 듯 합니다 ㅎㅎ;)

우리가 만든 예제와 다른 점이 있었다면,

입력값 양쪽에 command가 있어서 /bin/bash의 양쪽에 모두 ;을 씌어줬다는 정도가 되겠습니다 ㅎㅎㅎㅎㅎ 쉽죠잉?? ㅎㅎㅎ


.

.

.


와 이렇게 문제가 간단하고 쉽나? 모든 Command Injection 문제가 다 이런 거야?


착각은 금물입니다 ㅎㅎㅎ

언제나 시작은 가볍고 즐겁게 흥미를 돋우기 위한 과정일 뿐이죠 ㅎㅎㅎ

다음 시간 더 재미있는(쿄쿄) 문제로 찾아뵐게요 뿅뿅




마무으리


어때윰? 이제 Command Injection을 알게 된 것 같나윰?? ㅎㅎㅎ

감잡으셨나요? 감잡았으??? ㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎ

(삼천포 잡담인데 말이죠 ㅋㅋㅋㅋ 옛날에 친구랑 어디 돌아다니면서 놀다가 제가 “감잡았(으)~” 이랬는데….ㅋㅋㅋㅋ

칭구가 ㅇㅅㅇ;;??! 하는 표정인 거에요 ㅋㅋㅋㅋㅋㅋㅋㅋ 친구가 뭐라고 알아들었을까요? ㅋㅋㅋㅋㅋ

제가 “감자~밭!!!” 이라고 하는 줄 알고 얘 뭥미;;;;;; 한거래영 쿄쿄쿜)

여러분 감자밭??! ㅋ



그래도 지난 시간에 막막! 기초기초핵쉬운 거 *디다보다가 실습 위주로 이것 저것 해보니까 재미나지않았숨꽈? ㅎㅎㅎ

*디다보다가 = ‘들여다보다가’의 사투리입니다(친절 크크)


그래서 다음 시간에는 더더 재미있는!!! 진짜 실습을 해보려구요 ㅎㅎㅎ

오늘은 핵 간단 프로그램 것두 재미없게 제가 만든 거!로 Command Injection 해본 거구…

다음 시간에는 실!제!로! CTF에 출제된 Command Injection 관련 문제를 풀어보려고 합니다 ㅎㅎㅎ (feat. babycmd, DefCon2015 )

(마지막에 함께 풀어본 ftz3는 핵쉬운 맛보기~였습니다 후훟)


아 이제 저도 초짜인데… 함께 초짜인데… 잘 해낼 수 있을까 걱정도 되옵니다만 최선을 다해 삽질해보겠어요 ㅎㅎㅎ


그럼……………. 우린이제 안뇨옹~ 20000~


comments powered by Disqus