Drupal V7.3.1 架構處理不當導致SQL注入

來源:互聯網
上載者:User

標籤:update   tab   inter   oba   編譯   statement   rate   any   new   

  這個漏洞本是2014年時候被人發現的,本著學習的目的,我來做個詳細的分析。漏洞雖然很早了,新版的Drupal甚至已經改變了架構的組織方式。但是絲毫不影響對於漏洞的分析。這是一個經典的使用PDO,但是處理不當,導致SQL語句拼接從而導致注入的問題。從這個問題,以及以往我見過的很多的漏洞來看,我不得不說,代碼底層做的再安全,過濾的再完全,如果程式員的一個不小心,也將會導致重大安全問題的出現。多少的編碼繞過,邏輯漏洞正是不小心帶來的問題。

  0x00 注入的定位

  首先我根據網路上已經出現過的EXP,然後進行追蹤。無奈,這個架構實在太大,我在跟進的過程中,遇到了諸多的問題,甚至路由模式都沒有搞的很明白。然後根據已有的漏洞細節,我迅速定位到了漏洞的發生點。

  在檔案 \modules\user\user.module 中 有 user_login_authenticate_validate() 函數,代碼如下:

  

function user_login_authenticate_validate($form, &$form_state) {  $password = trim($form_state[‘values‘][‘pass‘]);  if (!empty($form_state[‘values‘][‘name‘]) && !empty($password)) {    // Do not allow any login from the current user‘s IP if the limit has been    // reached. Default is 50 failed attempts allowed in one hour. This is    // independent of the per-user limit to catch attempts from one IP to log    // in to many different user accounts.  We have a reasonably high limit    // since there may be only one apparent IP for all users at an institution.    if (!flood_is_allowed(‘failed_login_attempt_ip‘, variable_get(‘user_failed_login_ip_limit‘, 50), variable_get(‘user_failed_login_ip_window‘, 3600))) {      $form_state[‘flood_control_triggered‘] = ‘ip‘;      return;    }    $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(‘:name‘ => $form_state[‘values‘][‘name‘]))->fetchObject();  //省略無關代碼...

 

很明顯,這裡的SQL查詢就是漏洞觸發現場了,我們跟進db_query這個函數,代碼如下:

  

function db_query($query, array $args = array(), array $options = array()) {  if (empty($options[‘target‘])) {    $options[‘target‘] = ‘default‘;  }  return Database::getConnection($options[‘target‘])->query($query, $args, $options);}

繼續跟進query函數:

  public function query($query, array $args = array(), $options = array()) {    // Use default values if not already set.    $options += $this->defaultOptions();    try {      // We allow either a pre-bound statement object or a literal string.      // In either case, we want to end up with an executed statement object,      // which we pass to PDOStatement::execute.      if ($query instanceof DatabaseStatementInterface) {        $stmt = $query;        $stmt->execute(NULL, $options);      }      else {        $this->expandArguments($query, $args);        $stmt = $this->prepareQuery($query);        $stmt->execute($args, $options);      }    //省略無關代碼...

我們知道,如果在PHP串連MySQL資料庫中,如果我們使用PDO進行先行編譯的話,我們的語句是無法改變原有的查詢結構的,也就是說,注入的語句,無法進行查詢,只能是當做字串。從而從資料庫查詢層對注入做了徹底防禦。那麼這裡是怎麼產生問題的呢?

0x01 錯誤的處理導致的安全問題

  但是這裡有個問題,就是當參數是數組的時候,就會用到expandArguments這個方法,然後這個方法由於處理不當會導致安全問題。

  函數代碼如下:

  

  protected function expandArguments(&$query, &$args) {    $modified = FALSE;    // If the placeholder value to insert is an array, assume that we need    // to expand it out into a comma-delimited set of placeholders.    foreach (array_filter($args, ‘is_array‘) as $key => $data) {      $new_keys = array();      foreach ($data as $i => $value) {        // This assumes that there are no other placeholders that use the same        // name.  For example, if the array placeholder is defined as :example        // and there is already an :example_2 placeholder, this will generate        // a duplicate key.  We do not account for that as the calling code        // is already broken if that happens.        $new_keys[$key . ‘_‘ . $i] = $value;      }      // Update the query with the new placeholders.      // preg_replace is necessary to ensure the replacement does not affect      // placeholders that start with the same exact text. For example, if the      // query contains the placeholders :foo and :foobar, and :foo has an      // array of values, using str_replace would affect both placeholders,      // but using the following preg_replace would only affect :foo because      // it is followed by a non-word character.      $query = preg_replace(‘#‘ . $key . ‘\b#‘, implode(‘, ‘, array_keys($new_keys)), $query);      // Update the args array with the new placeholders.      unset($args[$key]);      $args += $new_keys;      $modified = TRUE;    }    return $modified;  }

我們再來回顧一下之前的查詢語句,

db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(‘:name‘ => $form_state[‘values‘][‘name‘]))

這個數組我們是可控的,首先在array_filter之後,使用foreach進行遍曆,然後二輪遍曆中建立了一個新的數組。接著把$query變數中的鍵,進行了替換,替換掉以後的內容是之前新數組鍵用 ‘, ‘進行合并成的一個新的字串。這樣我們通過鍵來進行SQL注入就行的通了。注入語句將會通過拼接進入。

0x03 測試

可以看得很清楚,name數組中的兩個鍵都被拼接進了SQL查詢。

 

0x04 反思

 這裡是挺有意思,也很常見的一個問題。我在開頭的引言中也說了。本來是做好了處理的,但是卻使用了拼接,導致可控的外部資料進入了SQL查詢。類似這樣的問題還很常見,當然了,這也為自己挖洞提供了思路,在挖洞越來越困難的當下,挖洞思路的變化顯得十分重要了。

 

  

Drupal V7.3.1 架構處理不當導致SQL注入

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.