취약점 개요

사용자가 계좌 입금, 계좌 이체, 상품 결재 등 중요한 기능이 있는 모바일 앱을 이용할 때 정확한 인증 절차를 거치고 기능을 사용할 수 있도록 해야 한다.

하지만, 인시큐어뱅크 앱의 계좌 이체 기능을 이용할 때, 인증 절차가 구현되어 있지 않아 송신자의 계좌번호를 변조하면 다른 사람의 계좌 번호에서 금액을 이체할 수 있는 취약점이 존재한다.

즉, 모바일 앱에 로그인을 한 사용자가 계좌 이체할 때 기재한 송신자의 계좌 번호가 일치 여부 검증 로직이 구현되어 있지 않는다.


취약점 진단

SQLite Browser 프로그램으로 서버 소스 디렉토리에 저장된 mydb.db 파일을 열면 데이터베이스 정보를 파싱하여 사용자의 계좌 정보를 보여준다.

Browse Data > Table : accounts 순서로 선택하면 회원 가입이 되어 있는 각 사용자의 계좌 번호, 보유 금액 정보가 저장되어 있다.

accounts 테이블 구조를 자세히 살펴보면 dinesh 사용자는 총 3개의 계좌 번호(123456789, 888888888, 666666666)를 가지고 있고, 계좌 번호별 금액(balance)은 다르게 설정되어 있다.


666666666 계좌는 수신자(to)의 계좌 번호이므로 다른 사용자에게 계좌 이체를 할 수 없고, 돈을 입금 받을 때 사용하는 계좌 번호이다.


mydb.db 파일 : Android-InsecureBankv2-master\AndroLabServer\mydb.db



인시큐어뱅크 모바일 앱을 실행하여 dinesh 사용자로 로그인을 한다.

DoTransfer > Get Accounts 순서로 메뉴를 클릭하면 상기 이미지의 mydb.db 파일 구조에서 확인한 결과와 동일하게 송신자 계좌 번호(From), 수신자 계좌 번호(To)가 888888888, 666666666 으로 채워진다.



이체 금액(Amount)을 1000으로 입력하고, Transfer 버튼을 클릭한다. mydb.db 파일을 보면 dinesh 사용자의 888888888 계좌 번호의 금액이 1000원 감소되고, 666666666 계좌 번호의 금액이 1000원 증가된다.



dinesh 사용자로 로그인을 한 상태에서 송신자 계좌 번호를 jack 사용자의 송신자 계좌 번호(987654321)로 변조하고, 자신의 계좌 번호(666666666 )로 계좌 이체를 시도한다.

정확한 인증 절차가 구현되어 있으면 계좌 이체가 실패한다. 하지만, 인증 절차가 구현되어 있지 않으므로 jack 사용자의 계좌 번호 금액이 1000원 감소되고, dinesh 사용자의 계좌 번호 금액이 1000원 증가된다.



Get Accounts 메뉴를 클릭 시 패킷을 캡처해보면 현재 로그인을 한 사용자의 계정 정보를 getaccounts 서버 주소로 요청한다. 만약, 계정 정보가 일치하면 사용자에게 계좌 번호 정보를 제공한다.



이체 금액을 입력하고 계좌 이체 메뉴를 클릭 시 패킷을 캡처해보면 로그인을 한 사용자의 계정 정보, 송신자의 계좌 번호, 수신자의 계좌 번호, 이체 금액을 dotransfer 서버 주소로 요청한다.


만약, 에러 없이 정상적으로 처리되면 서버는 사용자에게 계좌 이체가 성공되었다는 성공 메시지를 출력한다.



사용자가 Transfer 메뉴를 클릭하면 서버 소스코드(app.py)의 dotransfer() 메소드가 호출되어 실행된다.

소스코드를 보면 로그인을 한 사용자의 아이디가 데이터베이스에 존재 유무, 패스워드가 일치 유무의 검증만 확인하고, 로그인한 사용자의 계좌 번호와 송신자의 계좌 번호가 일치하는지 검증 로직이 구현되어 있지 않아 취약점이 발생한다.


app.py 파일 : Android-InsecureBankv2-master\AndroLabServer\app.py


@app.route('/dotransfer', methods=['POST'])
def dotransfer():
    #set accounts from the request 
    Responsemsg="fail"
    user=request.form['username']
    amount=request.form['amount']
    #print request.form["from_acc"]
    u = User.query.filter(User.username == user).first() #checks for presence of user in the database
    if not u or u.password != request.form["password"]:
        Responsemsg="Wrong Credentials so trx fail"
	#print Responsemsg
    else:
	Responsemsg="Success"
	#print Responsemsg
	from_acc = request.form["from_acc"]
	to_acc = request.form["to_acc"]
	amount = request.form["amount"]
        from_account = Account.query.filter(Account.account_number == from_acc).first()
        to_account = Account.query.filter(Account.account_number == to_acc).first()
	#print "fromacc=",from_account
        #print "amount===",amount
        to_account.balance += int(request.form['amount'])
        from_account.balance -= int(request.form['amount'])
        db_session.commit()
    data = {"message" : Responsemsg, "from": from_acc, "to": to_acc,  "amount": amount}

대응 방안 및 검증

인증 취약점은 로그인을 한 사용자의 계정 정보만 인증이 구현되어 있어 발생한다. 이를 해결하려면 사용자에게 계좌 비밀번호를 요구하거나 계좌 번호가 해당 사용자가 맞는지 등 인증 코드를 추가하면 중요 정보 유출을 막을 수 있다.


인증 취약점
서버 소스코드에 계좌 번호 존재, 계좌 비밀번호, SMS, OTP, 공인인증서 등 인증 로직을 구현되도록 수정

▶ Android Drozer 설치 및 사용법

▶ 안드로이드 컴포넌트 취약점 (Android Activity)

▶ 안드로이드 컴포넌트 취약점 (Android Broadcast Receiver)

▶ 안드로이드 컴포넌트 취약점 (Android Content Provider)

▶ 안드로이드 백업 취약점 (Android Backup)

▶ 안드로이드 메모리 노출 취약점 (메모리 덤프)

▶ 안드로이드 키보드캐시 취약점

▶ 안드로이드 난독화 (코드 보호 기법)

▶ 안드로이드 루팅 탐지 우회 (Frida Hooking)

▶ 안드로이드 로컬 암호화 취약점 (Android Local Encryption)

▶ 안드로이드 다중 사용자 로그인 취약점

▶ 안드로이드 웹뷰 취약점 (Android Webview)

▶ 안드로이드 SD카드 저장소 취약점 (Android SDCard Storage)

▶ 안드로이드 하드코딩 취약점 (Android Hardcoded Secrets)

▶ 안드로이드 HTTP 통신 취약점 (Android Insecure HTTP Connections)

▶ 안드로이드 사용자 계정 목록화 취약점 (Android Username Enumeration)

▶ 안드로이드 인시큐어뱅크 앱 설치 (Android InsecureBankv2)

▶ 안드로이드 개발자 백도어 취약점 (Android Developer Backdoors)

▶ 안드로이드 로깅 메커니즘 취약점 (Android Logging Mechanism)

  • 카카오톡-공유
  • 네이버-블로그-공유
  • 네이버-밴드-공유
  • 페이스북-공유
  • 트위터-공유
  • 카카오스토리-공유