2P by neo 23일전 | favorite | 댓글 1개

Arc의 클라우드 기능 소개

  • Arc를 사용하려면 계정이 필요함
  • Firebase를 인증에 사용함
  • 'Easels'라는 화이트보드 같은 기능이 있음
  • 공유 버튼을 클릭해도 mitmproxy에 요청이 나타나지 않음

Objective-C 기반 Firebase 앱 해킹

  • Firestore를 사용하여 백엔드를 작성하지 않고 데이터베이스 보안 규칙만 작성함
  • Firestore는 Swift SDK에서 시스템 프록시 설정을 따르지 않음
  • Frida 스크립트를 작성하여 관련 호출을 덤프함
var documentWithPath = ObjC.classes.FIRCollectionReference["- documentWithPath:"];
var queryWhereFieldIsEqualTo = ObjC.classes.FIRQuery["- queryWhereField:isEqualTo:"];
var collectionWithPath = ObjC.classes.FIRFirestore["- collectionWithPath:"];

function getFullPath(obj) {
  if (obj.path && typeof obj.path === "function") {
    return obj.path().toString();
  }
  return obj.toString();
}

var queryStack = [];

function logQuery(query) {
  var queryString = `firebase.${query.type}("${query.path}")`;
  query.whereClauses.forEach((clause) => {
    queryString += `.where("${clause.fieldName}", "==", "${clause.value}")`;
  });
  console.log(queryString);
}

Interceptor.attach(documentWithPath.implementation, {
  onEnter: function (args) {
    var parent = ObjC.Object(args[0]);
    var docPath = ObjC.Object(args[2]).toString();
    var fullPath = getFullPath(parent) + "/" + docPath;
    var query = { type: "doc", path: fullPath, whereClauses: [] };
    queryStack.push(query);
    logQuery(query);
  },
});

Interceptor.attach(collectionWithPath.implementation, {
  onEnter: function (args) {
    var collectionPath = ObjC.Object(args[2]).toString();
    var query = { type: "collection", path: collectionPath, whereClauses: [] };
    queryStack.push(query);
  },
});

Interceptor.attach(queryWhereFieldIsEqualTo.implementation, {
  onEnter: function (args) {
    var fieldName = ObjC.Object(args[2]).toString();
    var value = ObjC.Object(args[3]).toString();

    if (queryStack.length > 0) {
      var currentQuery = queryStack[queryStack.length - 1];
      currentQuery.whereClauses.push({ fieldName: fieldName, value: value });
    }
  },
  onLeave: function (retval) {},
});

var executionMethods = [
  "- getDocuments",
  "- addSnapshotListener:",
  "- getDocument",
  "- addDocumentSnapshotListener:",
  "- getDocumentsWithCompletion:",
  "- getDocumentWithCompletion:",
];

executionMethods.forEach(function (methodName) {
  if (ObjC.classes.FIRQuery[methodName]) {
    Interceptor.attach(ObjC.classes.FIRQuery[methodName].implementation, {
      onEnter: function (args) {
        if (queryStack.length > 0) {
          var query = queryStack.pop();
          logQuery(query);
        }
      },
    });
  }
});

function formatFirestoreData(data) {
  if (data.isKindOfClass_(ObjC.classes.NSDictionary)) {
    let result = {};
    data.enumerateKeysAndObjectsUsingBlock_(
      ObjC.implement(function (key, value) {
        result[key.toString()] = value.toString();
      })
    );
    return JSON.stringify(result);
  }
  return data.toString();
}

var documentMethods = [
  { name: "- updateData:completion:", type: "update" },
  { name: "- updateData:", type: "update" },
  { name: "- setData:completion:", type: "set" },
  { name: "- setData:", type: "set" },
];

documentMethods.forEach(function (method) {
  if (ObjC.classes.FIRDocumentReference[method.name]) {
    Interceptor.attach(
      ObjC.classes.FIRDocumentReference[method.name].implementation,
      {
        onEnter: function (args) {
          var docRef = ObjC.Object(args[0]);
          var data = ObjC.Object(args[2]);
          var fullPath = getFullPath(docRef);
          var formattedData = formatFirestoreData(data);
          console.log(
            `firebase.doc("${fullPath}").${method.type}(${formattedData})`
          );
        },
      }
    );
  } else {
    console.log("Warning: " + method.name + " not found");
  }
});
  • Arc가 Firestore에 사용자 기본 설정, 사용자 객체, 추천 및 부스트를 저장함

Arc 부스트란 무엇인가

  • Arc 부스트는 사용자가 웹사이트를 커스터마이징할 수 있는 방법임
  • 요소 차단, 글꼴 변경, 색상 변경, 사용자 정의 CSS 및 JS 사용 가능
  • 부스트를 생성하고 다른 사용자 ID로 업데이트할 수 있음

다른 사용자의 ID 얻기

  • 사용자 추천: 추천 테이블에서 사용자 ID를 얻을 수 있음
  • 공개 부스트: 부스트 스냅샷에 생성자의 사용자 ID가 포함됨
  • 사용자 이젤: 이젤을 공유하여 사용자 ID를 얻을 수 있음

최종 공격 체인

  • 피해자의 사용자 ID를 얻음
  • 악성 부스트를 생성하고 자신의 계정에 저장함
  • 부스트의 creatorID 필드를 타겟의 ID로 업데이트함
  • 피해자가 타겟 웹사이트를 방문하면 감염됨

특권 페이지에서의 RCE

  • 부스트가 다른 프로토콜에서도 실행됨
  • chrome://settings 페이지에서 특권 상승 가능

개인정보 보호 문제

  • 방문하는 사이트에 대한 데이터가 서버로 전송됨
  • Arc의 개인정보 보호 정책에 위배됨

GN⁺의 정리

  • Arc의 클라우드 기능과 보안 취약점을 분석한 기사임
  • Firestore를 활용한 백엔드 보안 문제를 다룸
  • Arc 부스트를 통한 사용자 커스터마이징과 보안 취약점 설명
  • 다른 사용자의 ID를 얻어 악성 부스트를 실행하는 방법을 제시함
  • 개인정보 보호 문제와 특권 상승 가능성에 대한 우려를 제기함
Hacker News 의견
  • Arc 브라우저의 보안 취약점은 용서할 수 없는 수준이며, 이로 인해 Arc를 다시는 사용하지 않을 것임
  • 클릭할 때마다 달려오는 픽셀 아트 고양이가 재미있고 인터넷이 즐거운 공간이 될 수 있음을 상기시켜줌
  • Arc 브라우저를 사용하는 사람들에게 경고하기 위해 게시물 제목에 Arc를 추가할 필요가 있음
  • Arc는 계정을 요구하고 사용자가 방문하는 모든 페이지의 호스트 이름과 사용자 ID를 Google의 Firebase에 전송함. 이는 Arc가 현재 사용 중인 가장 사생활 보호가 안 되는 웹 브라우저임을 의미함
  • Firebase 보안 규칙의 기본 설정이 이상하며, 경험이 있는 개발자는 클라이언트가 자신의 사용자 ID를 보호된 API 경로로 전달하도록 하지 않음
  • OP는 Arc 브라우저에 대해 이야기하고 있으며, Arc 언어나 다른 프로젝트와 혼동하지 말아야 함
  • Arc 브라우저는 오래가지 않을 것 같으며, Chrome이 가장 안전한 브라우저임. 새로운 소프트웨어 선택에 신중해야 함
  • $2000의 보상금은 큰 취약점에 비해 모욕적인 금액임
  • 블로그 게시물에서 언급된 'arc'가 무엇인지 궁금해하는 사람 있음. Arc 브라우저로 보임
  • 대문자가 제대로 사용되지 않아 읽기 어려운 기사임