0x01 考点与解析

其实这道题的原意是考察对JVM的了解

由于我们存在一个类的基地址泄露,加上Boss Know Everything的提示,最简单的思路应当是替换VIPPlayer与Boss的类,使VIPPlayer.toString()->Boss.toString(),即可获得FLAG

我们知道,Java的内存区域分为PC寄存器(Program Counter Register)Java虚拟机栈(Java Virtual Machine Stacks)本地方法栈(Native Method Stack)Java堆(Java Heap)方法区(Method Area).

我们知道,在C++层面,每一个Java Class都是一个instanceOop的实例,所以我们可以看看src/share/vm/oops/instanceOop.hpp[在线版戳这里],得到如下代码

#ifndef SHARE_VM_OOPS_INSTANCEOOP_HPP
#define SHARE_VM_OOPS_INSTANCEOOP_HPP
#include "oops/oop.hpp"

class instanceOopDesc : public oopDesc {
 public:
  // aligned header size.
  static int header_size() { return sizeof(instanceOopDesc)/HeapWordSize; }


  // If compressed, the offset of the fields of the instance may not be aligned.
  static int base_offset_in_bytes() {
    // offset computation code breaks if UseCompressedClassPointers
    // only is true

    return (UseCompressedOops && UseCompressedClassPointers) ?
             klass_gap_offset_in_bytes() :
             sizeof(instanceOopDesc);
  }


  static bool contains_field_offset(int offset, int nonstatic_field_size) {
    int base_in_bytes = base_offset_in_bytes();
    return (offset >= base_in_bytes &&
            (offset-base_in_bytes) < nonstatic_field_size * heapOopSize);
  }
};
#endif // SHARE_VM_OOPS_INSTANCEOOP_HPP

发现它继承自oopDesc[在线版戳这里]

1
2
3
4
5
6
7
8
9
10
class oopDesc {
friend class VMStructs;
private:
volatile markOop _mark;
union _metadata {
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata;
//省略一万行代码
}

所以,当我们new一个对象时,Jvm会帮我们在Java Heap中分配一块内存,结构为

+-------------------------+
| +---------------------+ |
| | instanceOopDesc     | |
| | +-----------------+ | |
| | | markOop  _mark  | | |
| | +-----------------+ | |
| | +-----------------+ | |
| | | union _metadata | | |
| | +-----------------+ | |
| +---------------------+ |
| +---------------------+ |
| | instanceData        | |
| +---------------------+ |
| +---------------------+ |
| | Pedding             | |
| |---------------------| |
+-------------------------+

题目描述所给的是Java 7 x86的环境,所以不存在指针压缩的问题,即此处_metadataKlass* _klass,另外,Java堆区的内存默认属性为rw,所以我们只需要互换Boss与VIPPlayer的InstanceAddress+4的值就行

P.S.:为啥会有VIPPlayer呢?我就想听你们夸我帅,哪怕不是真心的

0x02 题目解析

这个程序主要的东西都在

public String PraseCommand(String Command)

中,其中我们需要注意的是ShowInfo,Save,SetATK(SetHP),DebugSetDataStoreAddress

其中,Save暴露了两个类的基地址

DebugSetDataStoreAddress+ShowInfo可造成任意地址读

DebugSetDataStoreAddress+SetATK(SetHP)可造成任意地址写

所以此处就不额外放Exp了

另外,最关键的就是VeroFessIsHandsome(手动滑稽)

另外GetShell也是可选的高难度通关方法,但是有队师傅直接rm -rf /*了,至今不知道是谁…

前排推荐Nu1L大佬们的高难度通关姿势